diff options
Diffstat (limited to 'src')
72 files changed, 1148 insertions, 459 deletions
diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 4c30664d2..fa2d1b51d 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -45,6 +45,7 @@ import QtQuick.Controls.Private 1.0 \since 5.1 \inqmlmodule QtQuick.Controls \ingroup applicationwindow + \ingroup controls \brief Provides a top-level application window. \image applicationwindow.png diff --git a/src/controls/ComboBox.qml b/src/controls/ComboBox.qml index 8a2908b57..10702ff69 100644 --- a/src/controls/ComboBox.qml +++ b/src/controls/ComboBox.qml @@ -145,6 +145,50 @@ Control { */ property alias editText: input.text + /*! \qmlproperty enumeration ComboBox::inputMethodHints + \since QtQuick.Controls 1.5 + Provides hints to the input method about the expected content of the combo box and how it + should operate. + + The value is a bit-wise combination of flags or \c Qt.ImhNone if no hints are set. + + Flags that alter behavior are: + + \list + \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords. + \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method + in any persistent storage like predictive user dictionary. + \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case + when a sentence ends. + \li Qt.ImhPreferNumbers - Numbers are preferred (but not required). + \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required). + \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required). + \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing. + + \li Qt.ImhDate - The text editor functions as a date field. + \li Qt.ImhTime - The text editor functions as a time field. + \endlist + + Flags that restrict input (exclusive flags) are: + + \list + \li Qt.ImhDigitsOnly - Only digits are allowed. + \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign. + \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed. + \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed. + \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed. + \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed. + \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed. + \endlist + + Masks: + + \list + \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used. + \endlist + */ + property alias inputMethodHints: input.inputMethodHints + /*! This property specifies whether the combobox should gain active focus when pressed. The default value is \c false. */ property bool activeFocusOnPress: false @@ -511,6 +555,8 @@ Control { onTextRoleChanged: popup.resolveTextValue(textRole) + ExclusiveGroup { id: eg } + Menu { id: popup objectName: "popup" @@ -536,8 +582,6 @@ Control { __minimumWidth: comboBox.width __visualItem: comboBox - property ExclusiveGroup eg: ExclusiveGroup { id: eg } - property bool modelIsArray: false Instantiator { diff --git a/src/controls/Menu.qml b/src/controls/Menu.qml index 037fa550a..d485cb652 100644 --- a/src/controls/Menu.qml +++ b/src/controls/Menu.qml @@ -44,6 +44,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup menus + \ingroup controls \brief Provides a menu component for use as a context menu, popup menu, or as part of a menu bar. diff --git a/src/controls/MenuBar.qml b/src/controls/MenuBar.qml index 444185ccb..a16635ffa 100644 --- a/src/controls/MenuBar.qml +++ b/src/controls/MenuBar.qml @@ -44,6 +44,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup applicationwindow + \ingroup controls \brief Provides a horizontal menu bar. \image menubar.png diff --git a/src/controls/Private/AbstractCheckable.qml b/src/controls/Private/AbstractCheckable.qml index 42abebe58..bca626e09 100644 --- a/src/controls/Private/AbstractCheckable.qml +++ b/src/controls/Private/AbstractCheckable.qml @@ -41,7 +41,6 @@ import QtQuick.Controls.Private 1.0 /*! \qmltype AbstractCheckable \inqmlmodule QtQuick.Controls - \ingroup controls \brief An abstract representation of a checkable control with a label \qmlabstract \internal diff --git a/src/controls/Private/BasicButton.qml b/src/controls/Private/BasicButton.qml index 1756a296a..346cd419f 100644 --- a/src/controls/Private/BasicButton.qml +++ b/src/controls/Private/BasicButton.qml @@ -38,6 +38,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Controls.Private 1.0 import QtQuick.Controls.Styles 1.1 +import QtQuick.Window 2.2 /*! \qmltype BasicButton @@ -206,7 +207,7 @@ Control { Timer { interval: 1000 - running: behavior.containsMouse && !pressed && tooltip.length + running: behavior.containsMouse && !pressed && tooltip.length && behavior.Window.visibility !== Window.Hidden onTriggered: Tooltip.showText(behavior, Qt.point(behavior.mouseX, behavior.mouseY), tooltip) } } diff --git a/src/controls/Private/BasicTableView.qml b/src/controls/Private/BasicTableView.qml index 27635bc99..5fd211675 100644 --- a/src/controls/Private/BasicTableView.qml +++ b/src/controls/Private/BasicTableView.qml @@ -94,6 +94,7 @@ ScrollView { property Component itemDelegate: __style ? __style.itemDelegate : null /*! \qmlproperty Component BasicTableView::rowDelegate + \keyword basictableview-rowdelegate This property defines a delegate to draw a row. @@ -116,6 +117,7 @@ ScrollView { property Component rowDelegate: __style ? __style.rowDelegate : null /*! \qmlproperty Component BasicTableView::headerDelegate + \keyword basictableview-headerdelegate This property defines a delegate to draw a header. diff --git a/src/controls/Private/Control.qml b/src/controls/Private/Control.qml index f4733cc5f..4b965482e 100644 --- a/src/controls/Private/Control.qml +++ b/src/controls/Private/Control.qml @@ -72,19 +72,20 @@ FocusScope { property alias __styleData: styleLoader.styleData Loader { + id: styleLoader + sourceComponent: style + property Item __control: root + property QtObject styleData: null + onStatusChanged: { + if (status === Loader.Error) + console.error("Failed to load Style for", root) + } + } + + Loader { id: panelLoader anchors.fill: parent sourceComponent: __style ? __style.panel : null onStatusChanged: if (status === Loader.Error) console.error("Failed to load Style for", root) - Loader { - id: styleLoader - sourceComponent: style - property Item __control: root - property QtObject styleData: null - onStatusChanged: { - if (status === Loader.Error) - console.error("Failed to load Style for", root) - } - } } } diff --git a/src/controls/Private/EditMenu.qml b/src/controls/Private/EditMenu.qml index 51abe7588..a70e84074 100644 --- a/src/controls/Private/EditMenu.qml +++ b/src/controls/Private/EditMenu.qml @@ -45,8 +45,9 @@ Loader { property Item selectionHandle property Flickable flickable property Component defaultMenu: item && item.defaultMenu ? item.defaultMenu : null - property Menu menuInstance: null + property QtObject menuInstance: null property MouseArea mouseArea + property QtObject style: __style Connections { target: control @@ -67,6 +68,18 @@ Loader { return menuInstance; } - source: Qt.resolvedUrl(Qt.platform.os === "ios" ? "EditMenu_ios.qml" - : Qt.platform.os === "android" ? "" : "EditMenu_base.qml") + function syncStyle() { + if (!style) + return; + + if (style.__editMenu) + sourceComponent = style.__editMenu; + else { + // todo: get ios/android/base menus from style as well + source = (Qt.resolvedUrl(Qt.platform.os === "ios" ? "EditMenu_ios.qml" + : Qt.platform.os === "android" ? "" : "EditMenu_base.qml")); + } + } + onStyleChanged: syncStyle(); + Component.onCompleted: syncStyle(); } diff --git a/src/controls/Private/MenuContentItem.qml b/src/controls/Private/MenuContentItem.qml index a0b346c4c..e3be2e444 100644 --- a/src/controls/Private/MenuContentItem.qml +++ b/src/controls/Private/MenuContentItem.qml @@ -174,7 +174,7 @@ Loader { id: menuItemLoader Accessible.role: opts.type === MenuItemType.Item || opts.type === MenuItemType.Menu ? - Accessible.MenuItem : Acccessible.NoRole + Accessible.MenuItem : Accessible.NoRole Accessible.name: StyleHelpers.removeMnemonics(opts.text) Accessible.checkable: opts.checkable Accessible.checked: opts.checked diff --git a/src/controls/Private/TreeViewItemDelegateLoader.qml b/src/controls/Private/TreeViewItemDelegateLoader.qml index c4e13729c..8b8801fc9 100644 --- a/src/controls/Private/TreeViewItemDelegateLoader.qml +++ b/src/controls/Private/TreeViewItemDelegateLoader.qml @@ -98,6 +98,7 @@ TableViewItemDelegateLoader { visible: itemDelegateLoader.width > __itemIndentation sourceComponent: __style && __style.__branchDelegate || null anchors.right: parent.item ? parent.item.left : undefined + anchors.rightMargin: __style.__indentation > width ? (__style.__indentation - width) / 2 : 0 anchors.verticalCenter: parent.verticalCenter property QtObject styleData: itemDelegateLoader.styleData onLoaded: if (__rowItem) __rowItem.branchDecoration = item diff --git a/src/controls/Private/qquickcontrolsettings.cpp b/src/controls/Private/qquickcontrolsettings.cpp index 55850bf0a..8483830b6 100644 --- a/src/controls/Private/qquickcontrolsettings.cpp +++ b/src/controls/Private/qquickcontrolsettings.cpp @@ -98,6 +98,9 @@ bool QQuickControlSettings::isMobile() const #if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_QNX) || defined(Q_OS_WINRT) return true; #else + if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE")) { + return true; + } return false; #endif } @@ -112,7 +115,7 @@ QString QQuickControlSettings::makeStyleComponentPath(const QString &controlStyl return styleDirPath + QStringLiteral("/") + controlStyleName; } -QUrl QQuickControlSettings::makeStyleComponentUrl(const QString &controlStyleName, QString styleDirPath) +QUrl QQuickControlSettings::makeStyleComponentUrl(const QString &controlStyleName, const QString &styleDirPath) { QString styleFilePath = makeStyleComponentPath(controlStyleName, styleDirPath); diff --git a/src/controls/Private/qquickcontrolsettings_p.h b/src/controls/Private/qquickcontrolsettings_p.h index 1b99fd3ef..6a4e8c6ae 100644 --- a/src/controls/Private/qquickcontrolsettings_p.h +++ b/src/controls/Private/qquickcontrolsettings_p.h @@ -90,7 +90,7 @@ private: void findStyle(QQmlEngine *engine, const QString &styleName); bool resolveCurrentStylePath(); QString makeStyleComponentPath(const QString &controlStyleName, const QString &styleDirPath); - QUrl makeStyleComponentUrl(const QString &controlStyleName, QString styleDirPath); + QUrl makeStyleComponentUrl(const QString &controlStyleName, const QString &styleDirPath); struct StyleData { diff --git a/src/controls/Private/qquicktreemodeladaptor.cpp b/src/controls/Private/qquicktreemodeladaptor.cpp index 87b2808eb..666fafc9d 100644 --- a/src/controls/Private/qquicktreemodeladaptor.cpp +++ b/src/controls/Private/qquicktreemodeladaptor.cpp @@ -120,6 +120,29 @@ void QQuickTreeModelAdaptor::clearModelData() endResetModel(); } +const QModelIndex &QQuickTreeModelAdaptor::rootIndex() const +{ + return m_rootIndex; +} + +void QQuickTreeModelAdaptor::setRootIndex(const QModelIndex &idx) +{ + if (m_rootIndex == idx) + return; + + if (m_model) + clearModelData(); + m_rootIndex = idx; + if (m_model) + showModelTopLevelItems(); + emit rootIndexChanged(); +} + +void QQuickTreeModelAdaptor::resetRootIndex() +{ + setRootIndex(QModelIndex()); +} + QHash<int, QByteArray> QQuickTreeModelAdaptor::roleNames() const { if (!m_model) @@ -180,7 +203,7 @@ bool QQuickTreeModelAdaptor::setData(const QModelIndex &index, const QVariant &v int QQuickTreeModelAdaptor::itemIndex(const QModelIndex &index) const { // This is basically a plagiarism of QTreeViewPrivate::viewIndex() - if (!index.isValid() || m_items.isEmpty()) + if (!index.isValid() || index == m_rootIndex || m_items.isEmpty()) return -1; const int totalCount = m_items.count(); @@ -226,7 +249,7 @@ bool QQuickTreeModelAdaptor::isVisible(const QModelIndex &index) bool QQuickTreeModelAdaptor::childrenVisible(const QModelIndex &index) { - return (!index.isValid() && !m_items.isEmpty()) + return (index == m_rootIndex && !m_items.isEmpty()) || (m_expandedItems.contains(index) && isVisible(index)); } @@ -302,21 +325,21 @@ void QQuickTreeModelAdaptor::showModelTopLevelItems(bool doInsertRows) if (!m_model) return; - if (m_model->hasChildren(QModelIndex()) && m_model->canFetchMore(QModelIndex())) - m_model->fetchMore(QModelIndex()); - const long topLevelRowCount = m_model->rowCount(); + if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex)) + m_model->fetchMore(m_rootIndex); + const long topLevelRowCount = m_model->rowCount(m_rootIndex); if (topLevelRowCount == 0) return; - showModelChildItems(TreeItem(), 0, topLevelRowCount - 1, doInsertRows); + showModelChildItems(TreeItem(m_rootIndex), 0, topLevelRowCount - 1, doInsertRows); } void QQuickTreeModelAdaptor::showModelChildItems(const TreeItem &parentItem, int start, int end, bool doInsertRows, bool doExpandPendingRows) { const QModelIndex &parentIndex = parentItem.index; - int rowIdx = parentIndex.isValid() ? itemIndex(parentIndex) + 1 : 0; + int rowIdx = parentIndex.isValid() && parentIndex != m_rootIndex ? itemIndex(parentIndex) + 1 : 0; Q_ASSERT(rowIdx == 0 || parentItem.expanded); - if (parentIndex.isValid() && (rowIdx == 0 || !parentItem.expanded)) + if (parentIndex.isValid() && parentIndex != m_rootIndex && (rowIdx == 0 || !parentItem.expanded)) return; if (m_model->rowCount(parentIndex) == 0) { @@ -603,8 +626,11 @@ void QQuickTreeModelAdaptor::modelRowsInserted(const QModelIndex & parent, int s ASSERT_CONSISTENCY(); return; } - } else if (parent.isValid()) { + } else if (parent == m_rootIndex) { item = TreeItem(parent); + } else { + ASSERT_CONSISTENCY(); + return; } showModelChildItems(item, start, end); ASSERT_CONSISTENCY(); @@ -612,10 +638,8 @@ void QQuickTreeModelAdaptor::modelRowsInserted(const QModelIndex & parent, int s void QQuickTreeModelAdaptor::modelRowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) { - Q_UNUSED(start); - Q_UNUSED(end); ASSERT_CONSISTENCY(); - if (!parent.isValid() || childrenVisible(parent)) { + if (parent == m_rootIndex || childrenVisible(parent)) { const QModelIndex &smi = m_model->index(start, 0, parent); int startIndex = itemIndex(smi); const QModelIndex &emi = m_model->index(end, 0, parent); @@ -756,9 +780,9 @@ bool QQuickTreeModelAdaptor::testConsistency(bool dumpOnFail) const } return true; } - QModelIndex parent; + QModelIndex parent = m_rootIndex; QStack<QModelIndex> ancestors; - QModelIndex idx = m_model->index(0, 0); + QModelIndex idx = m_model->index(0, 0, parent); for (int i = 0; i < m_items.count(); i++) { bool isConsistent = true; const TreeItem &item = m_items.at(i); diff --git a/src/controls/Private/qquicktreemodeladaptor_p.h b/src/controls/Private/qquicktreemodeladaptor_p.h index 2297c3657..3eefbe776 100644 --- a/src/controls/Private/qquicktreemodeladaptor_p.h +++ b/src/controls/Private/qquicktreemodeladaptor_p.h @@ -61,6 +61,7 @@ class QQuickTreeModelAdaptor : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex RESET resetRootIndex NOTIFY rootIndexChanged) struct TreeItem; @@ -68,6 +69,9 @@ public: explicit QQuickTreeModelAdaptor(QObject *parent = 0); QAbstractItemModel *model() const; + const QModelIndex &rootIndex() const; + void setRootIndex(const QModelIndex &idx); + void resetRootIndex(); enum { DepthRole = Qt::UserRole - 4, @@ -110,6 +114,7 @@ public: signals: void modelChanged(QAbstractItemModel *model); + void rootIndexChanged(); void expanded(const QModelIndex &index); void collapsed(const QModelIndex &index); @@ -149,6 +154,7 @@ private: }; QPointer<QAbstractItemModel> m_model; + QPersistentModelIndex m_rootIndex; QList<TreeItem> m_items; QSet<QPersistentModelIndex> m_expandedItems; QList<TreeItem *> m_itemsToExpand; diff --git a/src/controls/ScrollView.qml b/src/controls/ScrollView.qml index 5c21848ff..74d5ee7dd 100644 --- a/src/controls/ScrollView.qml +++ b/src/controls/ScrollView.qml @@ -44,6 +44,7 @@ import QtQuick.Controls.Styles 1.1 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup views + \ingroup controls \brief Provides a scrolling view within another Item. \image scrollview.png diff --git a/src/controls/SpinBox.qml b/src/controls/SpinBox.qml index 96d8d0a21..aa7ccb1c8 100644 --- a/src/controls/SpinBox.qml +++ b/src/controls/SpinBox.qml @@ -132,6 +132,15 @@ Control { */ property alias font: input.font + /*! + \qmlproperty int SpinBox::cursorPosition + \since QtQuick.Controls 1.5 + + This property holds the position of the cursor in the SpinBox. + */ + property alias cursorPosition: input.cursorPosition + + /*! This property indicates whether the Spinbox should get active focus when pressed. The default value is \c true. diff --git a/src/controls/SplitView.qml b/src/controls/SplitView.qml index 41c50329a..c2e361acd 100644 --- a/src/controls/SplitView.qml +++ b/src/controls/SplitView.qml @@ -45,6 +45,7 @@ import QtQuick.Window 2.1 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup views + \ingroup controls \brief Lays out items with a draggable splitter between each item. \image splitview.png diff --git a/src/controls/StackView.qml b/src/controls/StackView.qml index 267727817..c76459ffc 100644 --- a/src/controls/StackView.qml +++ b/src/controls/StackView.qml @@ -42,6 +42,7 @@ import QtQuick.Controls.Private 1.0 \qmltype StackView \inherits Item \ingroup views + \ingroup controls \inqmlmodule QtQuick.Controls \since 5.1 diff --git a/src/controls/StackViewDelegate.qml b/src/controls/StackViewDelegate.qml index c837c2815..a1dacb215 100644 --- a/src/controls/StackViewDelegate.qml +++ b/src/controls/StackViewDelegate.qml @@ -39,6 +39,7 @@ import QtQuick 2.2 /*! \qmltype StackViewDelegate \inqmlmodule QtQuick.Controls + \ingroup controls \since 5.1 \brief A delegate used by StackView for loading transitions. diff --git a/src/controls/StatusBar.qml b/src/controls/StatusBar.qml index f151a3ac4..468d35872 100644 --- a/src/controls/StatusBar.qml +++ b/src/controls/StatusBar.qml @@ -43,6 +43,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup applicationwindow + \ingroup controls \brief Contains status information in your app. The common way of using StatusBar is in relation to \l ApplicationWindow. diff --git a/src/controls/Styles/Base/BasicTableViewStyle.qml b/src/controls/Styles/Base/BasicTableViewStyle.qml index 973d09c0b..c8d817c94 100644 --- a/src/controls/Styles/Base/BasicTableViewStyle.qml +++ b/src/controls/Styles/Base/BasicTableViewStyle.qml @@ -94,7 +94,8 @@ ScrollViewStyle { anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: styleData.textAlignment - anchors.leftMargin: 12 + anchors.leftMargin: horizontalAlignment === Text.AlignLeft ? 12 : 1 + anchors.rightMargin: horizontalAlignment === Text.AlignRight ? 8 : 1 text: styleData.value elide: Text.ElideRight color: textColor @@ -137,8 +138,9 @@ ScrollViewStyle { Text { id: label objectName: "label" - width: parent.width - x - x: styleData.depth && styleData.column === 0 ? 0 : 8 + width: parent.width - x - (horizontalAlignment === Text.AlignRight ? 8 : 1) + x: (styleData.hasOwnProperty("depth") && styleData.column === 0) ? 0 : + horizontalAlignment === Text.AlignRight ? 1 : 8 horizontalAlignment: styleData.textAlignment anchors.verticalCenter: parent.verticalCenter anchors.verticalCenterOffset: 1 diff --git a/src/controls/Styles/Base/ScrollViewStyle.qml b/src/controls/Styles/Base/ScrollViewStyle.qml index ed72951fc..09bc7da34 100644 --- a/src/controls/Styles/Base/ScrollViewStyle.qml +++ b/src/controls/Styles/Base/ScrollViewStyle.qml @@ -43,6 +43,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls.Styles \since 5.1 \ingroup viewsstyling + \ingroup controlsstyling \brief Provides custom styling for ScrollView */ Style { diff --git a/src/controls/Styles/Base/TabViewStyle.qml b/src/controls/Styles/Base/TabViewStyle.qml index 4842c39a3..94cc1240e 100644 --- a/src/controls/Styles/Base/TabViewStyle.qml +++ b/src/controls/Styles/Base/TabViewStyle.qml @@ -43,6 +43,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls.Styles \since 5.1 \ingroup viewsstyling + \ingroup controlsstyling \brief Provides custom styling for TabView \qml diff --git a/src/controls/Styles/Base/TextAreaStyle.qml b/src/controls/Styles/Base/TextAreaStyle.qml index 678d365dc..1da522272 100644 --- a/src/controls/Styles/Base/TextAreaStyle.qml +++ b/src/controls/Styles/Base/TextAreaStyle.qml @@ -146,4 +146,10 @@ ScrollViewStyle { \since QtQuick.Controls.Styles 1.3 */ property Component __cursorDelegate + + /*! \internal + The delegate for the cut/copy/paste menu. + \since QtQuick.Controls.Styles 1.4 + */ + property Component __editMenu } diff --git a/src/controls/Styles/Base/TextFieldStyle.qml b/src/controls/Styles/Base/TextFieldStyle.qml index e9247416d..b5e024b40 100644 --- a/src/controls/Styles/Base/TextFieldStyle.qml +++ b/src/controls/Styles/Base/TextFieldStyle.qml @@ -209,4 +209,10 @@ Style { \since QtQuick.Controls.Styles 1.3 */ property Component __cursorDelegate + + /*! \internal + The delegate for the cut/copy/paste menu. + \since QtQuick.Controls.Styles 1.4 + */ + property Component __editMenu } diff --git a/src/controls/Styles/Base/TreeViewStyle.qml b/src/controls/Styles/Base/TreeViewStyle.qml index b8f03f65c..e90542fed 100644 --- a/src/controls/Styles/Base/TreeViewStyle.qml +++ b/src/controls/Styles/Base/TreeViewStyle.qml @@ -43,10 +43,10 @@ BasicTableViewStyle { readonly property TreeView control: __control - property int indentation: 12 + property int indentation: 16 property Component branchDelegate: Item { - width: 16 + width: indentation height: 16 Text { visible: styleData.column === 0 && styleData.hasChildren @@ -54,8 +54,9 @@ BasicTableViewStyle { color: !control.activeFocus || styleData.selected ? styleData.textColor : "#666" font.pointSize: 10 renderType: Text.NativeRendering + style: Text.PlainText anchors.centerIn: parent - anchors.verticalCenterOffset: styleData.isExpanded ? 2 : 0 + anchors.verticalCenterOffset: 2 } } diff --git a/src/controls/Styles/Desktop/TableViewStyle.qml b/src/controls/Styles/Desktop/TableViewStyle.qml index f5199f3ff..1ead1b346 100644 --- a/src/controls/Styles/Desktop/TableViewStyle.qml +++ b/src/controls/Styles/Desktop/TableViewStyle.qml @@ -96,7 +96,10 @@ ScrollViewStyle { font: __styleitem.font anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: styleData["depth"] && styleData.column === 0 ? 0 : 8 + anchors.leftMargin: styleData.hasOwnProperty("depth") && styleData.column === 0 ? 0 : + horizontalAlignment === Text.AlignRight ? 1 : 8 + anchors.rightMargin: (styleData.hasOwnProperty("depth") && styleData.column === 0) + || horizontalAlignment !== Text.AlignRight ? 1 : 8 horizontalAlignment: styleData.textAlignment anchors.verticalCenter: parent.verticalCenter elide: styleData.elideMode diff --git a/src/controls/Styles/Desktop/TreeViewStyle.qml b/src/controls/Styles/Desktop/TreeViewStyle.qml index 1901c40cc..6424ed0e1 100644 --- a/src/controls/Styles/Desktop/TreeViewStyle.qml +++ b/src/controls/Styles/Desktop/TreeViewStyle.qml @@ -56,12 +56,12 @@ Desktop.TableViewStyle { hasFocus: __styleitem.active Component.onCompleted: { - implicitWidth = si.pixelMetric("treeviewindentation") + root.__indentation = si.pixelMetric("treeviewindentation") + implicitWidth = root.__indentation implicitHeight = implicitWidth var rect = si.subControlRect("dummy"); width = rect.width height = rect.height - root.__indentation = width } } } diff --git a/src/controls/Styles/iOS/SliderStyle.qml b/src/controls/Styles/iOS/SliderStyle.qml index 3d39ce2b9..8a87f809a 100644 --- a/src/controls/Styles/iOS/SliderStyle.qml +++ b/src/controls/Styles/iOS/SliderStyle.qml @@ -34,6 +34,54 @@ ** ****************************************************************************/ +import QtQuick 2.3 import QtQuick.Controls.Styles 1.3 -SliderStyle { } +SliderStyle { + groove: Rectangle { + implicitWidth: 20 + implicitHeight: 2 + + color: "#a8a8a8" + radius: 45.0 + + Rectangle { + width: styleData.handlePosition + height: parent.height + color: "#0a60ff" + radius: parent.radius + } + } + + handle: Item { + width: 29 + height: 32 + + Rectangle { + y: 3 + width: 29 + height: 29 + radius: 90.0 + + color: "#d6d6d6" + opacity: 0.2 + } + + Rectangle { + width: 29 + height: 29 + radius: 90.0 + + gradient: Gradient { + GradientStop { position: 0.0; color: "#e2e2e2" } + GradientStop { position: 1.0; color: "#d6d6d6" } + } + + Rectangle { + anchors.fill: parent + anchors.margins: 1 + radius: parent.radius + } + } + } +} diff --git a/src/controls/Tab.qml b/src/controls/Tab.qml index f5d02cf3a..07a4cd9e4 100644 --- a/src/controls/Tab.qml +++ b/src/controls/Tab.qml @@ -41,6 +41,7 @@ import QtQuick 2.2 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup viewaddons + \ingroup controls \brief Tab represents the content of a tab in a TabView. A Tab item inherits from Loader and provides a similar diff --git a/src/controls/TabView.qml b/src/controls/TabView.qml index bd043be9f..f7a8324a5 100644 --- a/src/controls/TabView.qml +++ b/src/controls/TabView.qml @@ -43,6 +43,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup views + \ingroup controls \brief A control that allows the user to select one of multiple stacked items. \image tabview.png diff --git a/src/controls/TableViewColumn.qml b/src/controls/TableViewColumn.qml index 9bcdfe6d5..3f5a84681 100644 --- a/src/controls/TableViewColumn.qml +++ b/src/controls/TableViewColumn.qml @@ -41,6 +41,7 @@ import QtQuick 2.2 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup viewitems + \ingroup controls \brief Used to define columns in a \l TableView or in a \l TreeView. \image tableview.png diff --git a/src/controls/TextArea.qml b/src/controls/TextArea.qml index 23360f06d..87b13e0dd 100644 --- a/src/controls/TextArea.qml +++ b/src/controls/TextArea.qml @@ -34,7 +34,7 @@ ** ****************************************************************************/ -import QtQuick 2.2 +import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Controls 1.2 import QtQuick.Controls.Private 1.0 @@ -423,6 +423,16 @@ ScrollView { signal linkHovered(string link) /*! + \qmlsignal TextArea::editingFinished() + \since QtQuick.Controls 1.5 + + This signal is emitted when the text area loses focus. + + The corresponding handler is \c onEditingFinished. + */ + signal editingFinished() + + /*! \qmlproperty string TextArea::hoveredLink \since QtQuick.Controls 1.1 @@ -819,6 +829,7 @@ ScrollView { onLinkActivated: area.linkActivated(link) onLinkHovered: area.linkHovered(link) + onEditingFinished: area.editingFinished() function activate() { if (activeFocusOnPress) { diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml index 589869d35..0c8a0df63 100644 --- a/src/controls/TextField.qml +++ b/src/controls/TextField.qml @@ -34,7 +34,7 @@ ** ****************************************************************************/ -import QtQuick 2.2 +import QtQuick 2.6 import QtQuick.Controls 1.2 import QtQuick.Controls.Private 1.0 @@ -660,6 +660,8 @@ Control { Keys.forwardTo: textfield + EnterKey.type: control.EnterKey.type + onAccepted: textfield.accepted() onEditingFinished: textfield.editingFinished() diff --git a/src/controls/ToolBar.qml b/src/controls/ToolBar.qml index 48f62f167..f5d0a994a 100644 --- a/src/controls/ToolBar.qml +++ b/src/controls/ToolBar.qml @@ -43,6 +43,7 @@ import QtQuick.Controls.Private 1.0 \inqmlmodule QtQuick.Controls \since 5.1 \ingroup applicationwindow + \ingroup controls \brief Contains ToolButton and related controls. \image toolbar.png diff --git a/src/controls/TreeView.qml b/src/controls/TreeView.qml index c97930f38..637c46c3c 100644 --- a/src/controls/TreeView.qml +++ b/src/controls/TreeView.qml @@ -44,6 +44,7 @@ BasicTableView { id: root property var model: null + property alias rootIndex: modelAdaptor.rootIndex readonly property var currentIndex: modelAdaptor.mapRowToModelIndex(__currentRow) property ItemSelectionModel selection: null diff --git a/src/controls/controls.pro b/src/controls/controls.pro index 7dd176f01..f725b1ced 100644 --- a/src/controls/controls.pro +++ b/src/controls/controls.pro @@ -1,6 +1,8 @@ +requires(contains(QT_CONFIG, accessibility)) + TARGET = qtquickcontrolsplugin TARGETPATH = QtQuick/Controls -IMPORT_VERSION = 1.4 +IMPORT_VERSION = 1.5 QT += qml quick quick-private qml-private gui-private core-private diff --git a/src/controls/doc/qtquickcontrols.qdocconf b/src/controls/doc/qtquickcontrols.qdocconf index e8aa04226..6ea7e7412 100644 --- a/src/controls/doc/qtquickcontrols.qdocconf +++ b/src/controls/doc/qtquickcontrols.qdocconf @@ -17,16 +17,22 @@ qhp.QtQuickControls.filterAttributes = qtquickcontrols $QT_VERSION qtrefdoc qhp.QtQuickControls.customFilters.Qt.name = QtQuickControls $QT_VERSION qhp.QtQuickControls.customFilters.Qt.filterAttributes = qtquickcontrols $QT_VERSION -qhp.QtQuickControls.subprojects = qtquickcontrolsqmltypes qtquickcontrolsstyles +qhp.QtQuickControls.subprojects = qqcqmltypes qqcstylesqmltypes qqcexamples -qhp.QtQuickControls.subprojects.qtquickcontrolsqmltypes.title = Controls QML Types -qhp.QtQuickControls.subprojects.qtquickcontrolsqmltypes.indexTitle = Qt Quick Controls QML Types -qhp.QtQuickControls.subprojects.qtquickcontrolsqmltypes.selectors = qmlclass # cannot choose qmltypes from a specific group QTBUG-32985 -qhp.QtQuickControls.subprojects.qtquickcontrolsqmltypes.sortPages = true +qhp.QtQuickControls.subprojects.qqcqmltypes.title = Controls QML Types +qhp.QtQuickControls.subprojects.qqcqmltypes.indexTitle = Qt Quick Controls QML Types +qhp.QtQuickControls.subprojects.qqcqmltypes.selectors = group:controls +qhp.QtQuickControls.subprojects.qqcqmltypes.sortPages = true -qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.title = Qt Quick Controls Styles Structure -qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.indexTitle = Qt Quick Controls Styles Structure -qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.type = manual +qhp.QtQuickControls.subprojects.qqcstylesqmltypes.title = Controls Styles QML Types +qhp.QtQuickControls.subprojects.qqcstylesqmltypes.indexTitle = Qt Quick Controls Styles QML Types +qhp.QtQuickControls.subprojects.qqcstylesqmltypes.selectors = group:controlsstyling +qhp.QtQuickControls.subprojects.qqcstylesqmltypes.sortPages = true + +qhp.QtQuickControls.subprojects.qqcexamples.title = Examples and Tutorials +qhp.QtQuickControls.subprojects.qqcexamples.indexTitle = Qt Quick Controls Examples +qhp.QtQuickControls.subprojects.qqcexamples.selectors = doc:example group:stylingtutorials +qhp.QtQuickControls.subprojects.qqcexamples.sortpages = true depends = qtcore qtdoc qtgui qtwidgets qtqml qtquick qtquicklayouts qtquickdialogs qtquickextras @@ -35,7 +41,7 @@ depends = qtcore qtdoc qtgui qtwidgets qtqml qtquick qtquicklayouts qtquickdialo # is given as part of \example commands exampledirs += ../../../examples/quick/controls \ snippets -examplesinstallpath = quick/controls +examplesinstallpath = qtquickcontrols/quick/controls headerdirs += .. diff --git a/src/controls/doc/src/qtquickcontrols-overview.qdoc b/src/controls/doc/src/qtquickcontrols-overview.qdoc index 45a4557a3..f549d0c8e 100644 --- a/src/controls/doc/src/qtquickcontrols-overview.qdoc +++ b/src/controls/doc/src/qtquickcontrols-overview.qdoc @@ -126,6 +126,10 @@ forgotten. This is a known limitation and a workaround is to add potentially missing imports in one of the qml files of the application using the controls. + \section2 Testing Desktop and Mobile behavior of the controls + You can test how the controls on your application or style will behave on + a mobile platform by setting the environment variable \e QT_QUICK_CONTROLS_MOBILE, to force a behavior optimized for mobile devices. + \section1 Related information \list diff --git a/src/controls/doc/src/qtquickcontrols-tableview.qdoc b/src/controls/doc/src/qtquickcontrols-tableview.qdoc index 15b99c18a..a9c6d22a9 100644 --- a/src/controls/doc/src/qtquickcontrols-tableview.qdoc +++ b/src/controls/doc/src/qtquickcontrols-tableview.qdoc @@ -31,6 +31,7 @@ \inherits BasicTableView \since 5.1 \ingroup views + \ingroup controls \brief Provides a list view with scroll bars, styling and header sections. \image tableview.png diff --git a/src/controls/doc/src/qtquickcontrols-treeview.qdoc b/src/controls/doc/src/qtquickcontrols-treeview.qdoc index fb1860599..8188e955e 100644 --- a/src/controls/doc/src/qtquickcontrols-treeview.qdoc +++ b/src/controls/doc/src/qtquickcontrols-treeview.qdoc @@ -31,6 +31,7 @@ \inherits BasicTableView \since 5.5 \ingroup views + \ingroup controls \brief Provides a tree view with scroll bars, styling and header sections. \image treeview.png @@ -63,8 +64,8 @@ the model role they attach to. Each property in the model will then be shown in their corresponding column. - You can customize the look by overriding the \l {TreeView::itemDelegate}{itemDelegate}, - \l {TreeView::rowDelegate}{rowDelegate}, or \l {TreeView::headerDelegate}{headerDelegate} properties. + You can customize the look by overriding the \l [QML]{TreeView::}{itemDelegate}, + \l {basictableview-rowdelegate}{rowDelegate}, or \l {basictableview-headerdelegate}{headerDelegate} properties. The view itself does not provide sorting. This has to be done on the model itself. However you can provide sorting @@ -142,6 +143,19 @@ */ /*! + \qmlproperty QModelIndex TreeView::rootIndex + The model index of the root item in the tree view. The root item is the + parent item to the view's top-level items. Only items descending from the + root item will be visible in the view. + + Its default value is an invalid QModelIndex, which means the whole + model data is shown by the tree view (assigning \c undefined to this + proprety resets it to its default value.) + + \since QtQuick.Controls 1.5 +*/ + +/*! \qmlproperty QModelIndex TreeView::currentIndex The model index of the current row in the tree view. */ diff --git a/src/controls/doc/src/qtquickcontrolsstyles-index.qdoc b/src/controls/doc/src/qtquickcontrolsstyles-index.qdoc index 94eb6fb49..792f064ca 100644 --- a/src/controls/doc/src/qtquickcontrolsstyles-index.qdoc +++ b/src/controls/doc/src/qtquickcontrolsstyles-index.qdoc @@ -125,17 +125,6 @@ */ /*! - \page qtquickcontrolsstyles-structure.html - \title Qt Quick Controls Styles Structure - \list - \li \l{Qt Quick Controls Styles} - \list - \li \l{Qt Quick Controls Styles QML Types}{Styles QMl Types} - \endlist - \endlist -*/ - -/*! \qmlmodule QtQuick.Controls.Styles 1.4 \title Qt Quick Controls Styles QML Types \ingroup qmlmodules diff --git a/src/controls/doc/src/qtquickcontrolsstyles-tableviewstyle.qdoc b/src/controls/doc/src/qtquickcontrolsstyles-tableviewstyle.qdoc index 0b5012f1d..c781f9036 100644 --- a/src/controls/doc/src/qtquickcontrolsstyles-tableviewstyle.qdoc +++ b/src/controls/doc/src/qtquickcontrolsstyles-tableviewstyle.qdoc @@ -31,6 +31,7 @@ \inherits BasicTableViewStyle \since 5.1 \ingroup viewsstyling + \ingroup controlsstyling \brief Provides custom styling for TableView */ diff --git a/src/controls/doc/src/qtquickcontrolsstyles-treeviewstyle.qdoc b/src/controls/doc/src/qtquickcontrolsstyles-treeviewstyle.qdoc index 3f4508f4e..e98b6cae8 100644 --- a/src/controls/doc/src/qtquickcontrolsstyles-treeviewstyle.qdoc +++ b/src/controls/doc/src/qtquickcontrolsstyles-treeviewstyle.qdoc @@ -31,6 +31,7 @@ \inherits BasicTableViewStyle \since 5.5 \ingroup viewsstyling + \ingroup controlsstyling \brief Provides custom styling for TreeView */ diff --git a/src/controls/plugin.cpp b/src/controls/plugin.cpp index 8ab956c64..e1afeef27 100644 --- a/src/controls/plugin.cpp +++ b/src/controls/plugin.cpp @@ -112,7 +112,10 @@ static const struct { { "TextArea", 1, 3 }, - { "TreeView", 1, 4 } + { "TreeView", 1, 4 }, + + { "TextArea", 1, 5 }, + { "TreeView", 1, 5 } }; void QtQuickControlsPlugin::registerTypes(const char *uri) diff --git a/src/controls/qquickaction.cpp b/src/controls/qquickaction.cpp index 90a1fd67b..6add916de 100644 --- a/src/controls/qquickaction.cpp +++ b/src/controls/qquickaction.cpp @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE \qmltype Action \instantiates QQuickAction \ingroup applicationwindow + \ingroup controls \inqmlmodule QtQuick.Controls \brief Action provides an abstract user interface action that can be bound to items diff --git a/src/controls/qquickaction_p.h b/src/controls/qquickaction_p.h index 1828cc9e6..e3b9c8528 100644 --- a/src/controls/qquickaction_p.h +++ b/src/controls/qquickaction_p.h @@ -104,7 +104,7 @@ public: QIcon icon() const { return m_icon; } QVariant iconVariant() const { return QVariant(m_icon); } - void setIcon(QIcon icon) { m_icon = icon; emit iconChanged(); } + void setIcon(const QIcon &icon) { m_icon = icon; emit iconChanged(); } bool event(QEvent *e); @@ -116,12 +116,12 @@ Q_SIGNALS: void toggled(bool checked); void textChanged(); - void shortcutChanged(QVariant shortcut); + void shortcutChanged(const QVariant &shortcut); void iconChanged(); void iconNameChanged(); void iconSourceChanged(); - void tooltipChanged(QString arg); + void tooltipChanged(const QString &arg); void enabledChanged(); void checkableChanged(); diff --git a/src/controls/qquickmenu.cpp b/src/controls/qquickmenu.cpp index beabe65b5..fec24189e 100644 --- a/src/controls/qquickmenu.cpp +++ b/src/controls/qquickmenu.cpp @@ -695,12 +695,12 @@ int QQuickMenu::indexOfMenuItem(QQuickMenuBase *item) const } } -QQuickMenuItem *QQuickMenu::addItem(QString title) +QQuickMenuItem *QQuickMenu::addItem(const QString &title) { return insertItem(m_itemsCount, title); } -QQuickMenuItem *QQuickMenu::insertItem(int index, QString title) +QQuickMenuItem *QQuickMenu::insertItem(int index, const QString &title) { QQuickMenuItem *item = new QQuickMenuItem(this); item->setText(title); diff --git a/src/controls/qquickmenu_p.h b/src/controls/qquickmenu_p.h index a626179ab..1c51fe716 100644 --- a/src/controls/qquickmenu_p.h +++ b/src/controls/qquickmenu_p.h @@ -77,8 +77,8 @@ public: enum MenuType { DefaultMenu = 0, EditMenu }; Q_INVOKABLE void popup(); - Q_INVOKABLE QQuickMenuItem *addItem(QString); - Q_INVOKABLE QQuickMenuItem *insertItem(int, QString); + Q_INVOKABLE QQuickMenuItem *addItem(const QString &); + Q_INVOKABLE QQuickMenuItem *insertItem(int, const QString &); Q_INVOKABLE void addSeparator(); Q_INVOKABLE void insertSeparator(int); diff --git a/src/controls/qquickmenuitem.cpp b/src/controls/qquickmenuitem.cpp index be15a435d..0702d398a 100644 --- a/src/controls/qquickmenuitem.cpp +++ b/src/controls/qquickmenuitem.cpp @@ -135,6 +135,7 @@ void QQuickMenuBase::setVisualItem(QQuickItem *item) \instantiates QQuickMenuSeparator \inqmlmodule QtQuick.Controls \ingroup menus + \ingroup controls \brief MenuSeparator provides a separator for items inside a menu. \image menu.png @@ -284,6 +285,7 @@ void QQuickMenuText::updateIcon() \qmltype MenuItem \instantiates QQuickMenuItem \ingroup menus + \ingroup controls \inqmlmodule QtQuick.Controls \brief MenuItem provides an item to add in a menu or a menu bar. diff --git a/src/controls/qquickpopupwindow.cpp b/src/controls/qquickpopupwindow.cpp index a8f451673..59cfe22bf 100644 --- a/src/controls/qquickpopupwindow.cpp +++ b/src/controls/qquickpopupwindow.cpp @@ -67,6 +67,7 @@ void QQuickPopupWindow::show() if (QWindow *tp = transientParent()) { if (m_parentItem) { QPointF pos = m_parentItem->mapToItem(m_parentItem->window()->contentItem(), QPointF(posx, posy)); + pos += tp->mapFromGlobal(m_parentItem->window()->mapToGlobal(QPoint())); posx = pos.x(); posy = pos.y(); } diff --git a/src/controls/qquickstack.cpp b/src/controls/qquickstack.cpp index 160316562..3524b9ef5 100644 --- a/src/controls/qquickstack.cpp +++ b/src/controls/qquickstack.cpp @@ -42,6 +42,7 @@ QT_BEGIN_NAMESPACE \qmltype Stack \instantiates QQuickStack \inqmlmodule QtQuick.Controls + \ingroup controls \brief Provides attached properties for items pushed onto a StackView. The Stack type provides attached properties for items pushed onto a \l StackView. diff --git a/src/dialogs/dialogs.pro b/src/dialogs/dialogs.pro index b0b9db2d1..9daaa6e6b 100644 --- a/src/dialogs/dialogs.pro +++ b/src/dialogs/dialogs.pro @@ -1,3 +1,5 @@ +requires(contains(QT_CONFIG, accessibility)) + CXX_MODULE = qml TARGET = dialogplugin TARGETPATH = QtQuick/Dialogs diff --git a/src/dialogs/doc/qtquickdialogs.qdocconf b/src/dialogs/doc/qtquickdialogs.qdocconf index 2dd08ed6f..30f3635a3 100644 --- a/src/dialogs/doc/qtquickdialogs.qdocconf +++ b/src/dialogs/doc/qtquickdialogs.qdocconf @@ -26,7 +26,7 @@ depends = qtqml qtquick qtgui qtwidgets qtdoc qtcore exampledirs += ../../../examples/quick/dialogs -examplesinstallpath = quick/dialogs +examplesinstallpath = qtquickcontrols/quick/dialogs headerdirs += .. diff --git a/src/dialogs/plugin.cpp b/src/dialogs/plugin.cpp index 7fac166df..657400245 100644 --- a/src/dialogs/plugin.cpp +++ b/src/dialogs/plugin.cpp @@ -175,7 +175,7 @@ public: protected: template <class WrapperType> - void registerWidgetOrQmlImplementation(QDir widgetsDir, QDir qmlDir, + void registerWidgetOrQmlImplementation(const QDir &widgetsDir, const QDir &qmlDir, const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor) { qCDebug(lcRegistration) << qmlName << uri << ": QML in" << qmlDir.absolutePath() << "using resources?" << m_useResources << "; widgets in" << widgetsDir.absolutePath(); @@ -191,7 +191,7 @@ protected: } template <class WrapperType> - bool registerWidgetImplementation(QDir widgetsDir, QDir qmlDir, + bool registerWidgetImplementation(const QDir &widgetsDir, const QDir &qmlDir, const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor) { @@ -223,7 +223,7 @@ protected: } template <class WrapperType> - void registerQmlImplementation(QDir qmlDir, const char *qmlName, const char *uri , int versionMajor, int versionMinor) + void registerQmlImplementation(const QDir &qmlDir, const char *qmlName, const char *uri , int versionMajor, int versionMinor) { qCDebug(lcRegistration) << "Register QML version for" << qmlName << "with uri:" << uri; diff --git a/src/extras/Styles/Flat/GroupBoxStyle.qml b/src/extras/Styles/Flat/GroupBoxStyle.qml index 65f8cf19b..e72c6075a 100644 --- a/src/extras/Styles/Flat/GroupBoxStyle.qml +++ b/src/extras/Styles/Flat/GroupBoxStyle.qml @@ -65,8 +65,8 @@ Private.GroupBoxStyle { // TODO: Binding { - target: root - property: "padding.top" + target: root.padding + property: "top" value: background.anchors.topMargin + root.spacing } diff --git a/src/extras/Tumbler.qml b/src/extras/Tumbler.qml index 7cba6ed0e..47cb043c7 100644 --- a/src/extras/Tumbler.qml +++ b/src/extras/Tumbler.qml @@ -177,20 +177,19 @@ Control { } /*! - \qmlmethod void Tumbler::setCurrentIndexAt(int columnIndex, int itemIndex) - Sets the current index of the column at \a columnIndex to \a itemIndex. + \qmlmethod void Tumbler::setCurrentIndexAt(int columnIndex, int itemIndex, int interval) + Sets the current index of the column at \a columnIndex to \a itemIndex. The animation + length can be set with \a interval, which defaults to \c 0. Does nothing if \a columnIndex or \a itemIndex are invalid. */ - function setCurrentIndexAt(columnIndex, itemIndex) { + function setCurrentIndexAt(columnIndex, itemIndex, interval) { if (!__isValidColumnAndItemIndex(columnIndex, itemIndex)) return; var view = columnRepeater.itemAt(columnIndex).view; if (view.currentIndex !== itemIndex) { - // Hack to work around the pathview jumping when the index is changed. - // TODO: doesn't seem to be necessary anymore? - view.highlightMoveDuration = 0; + view.highlightMoveDuration = typeof interval !== 'undefined' ? interval : 0; view.currentIndex = itemIndex; view.highlightMoveDuration = Qt.binding(function(){ return __highlightMoveDuration; }); } diff --git a/src/extras/doc/qtquickextras.qdocconf b/src/extras/doc/qtquickextras.qdocconf index a802d9fa8..747465fc0 100644 --- a/src/extras/doc/qtquickextras.qdocconf +++ b/src/extras/doc/qtquickextras.qdocconf @@ -30,7 +30,7 @@ qhp.QtQuickExtras.subprojects.qtquickextrasexamples.sortPages = true depends = qtqml qtquick qtdoc qtquickcontrols qtgui exampledirs += ../../../examples/quick/extras -examplesinstallpath = quick/extras +examplesinstallpath = qtquickcontrols/quick/extras headerdirs += ../ diff --git a/src/extras/extras.pro b/src/extras/extras.pro index 2ebd8f81b..4363ce005 100644 --- a/src/extras/extras.pro +++ b/src/extras/extras.pro @@ -1,3 +1,5 @@ +requires(contains(QT_CONFIG, accessibility)) + TARGET = qtquickextrasplugin TARGETPATH = QtQuick/Extras IMPORT_VERSION = 1.4 diff --git a/src/layouts/layouts.pro b/src/layouts/layouts.pro index 3ef18f85d..f7a73b7e3 100644 --- a/src/layouts/layouts.pro +++ b/src/layouts/layouts.pro @@ -10,12 +10,14 @@ QMAKE_DOCS = $$PWD/doc/qtquicklayouts.qdocconf SOURCES += plugin.cpp \ qquicklayout.cpp \ qquicklinearlayout.cpp \ + qquickstacklayout.cpp \ qquickgridlayoutengine.cpp \ qquicklayoutstyleinfo.cpp HEADERS += \ qquicklayout_p.h \ qquicklinearlayout_p.h \ + qquickstacklayout_p.h \ qquickgridlayoutengine_p.h \ qquicklayoutstyleinfo_p.h diff --git a/src/layouts/plugin.cpp b/src/layouts/plugin.cpp index fa72fa8d7..6a6705398 100644 --- a/src/layouts/plugin.cpp +++ b/src/layouts/plugin.cpp @@ -37,6 +37,7 @@ #include <QtQml/qqmlextensionplugin.h> #include "qquicklinearlayout_p.h" +#include "qquickstacklayout_p.h" QT_BEGIN_NAMESPACE @@ -54,6 +55,7 @@ public: qmlRegisterType<QQuickRowLayout>(uri, 1, 0, "RowLayout"); qmlRegisterType<QQuickColumnLayout>(uri, 1, 0, "ColumnLayout"); qmlRegisterType<QQuickGridLayout>(uri, 1, 0, "GridLayout"); + qmlRegisterType<QQuickStackLayout>(uri, 1, 3, "StackLayout"); qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 0, "Layout", QStringLiteral("Do not create objects of type Layout")); qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 2, "Layout", diff --git a/src/layouts/qquickgridlayoutengine.cpp b/src/layouts/qquickgridlayoutengine.cpp index 553f45d01..2c08eec18 100644 --- a/src/layouts/qquickgridlayoutengine.cpp +++ b/src/layouts/qquickgridlayoutengine.cpp @@ -40,261 +40,6 @@ QT_BEGIN_NAMESPACE -/* - The layout engine assumes: - 1. minimum <= preferred <= maximum - 2. descent is within minimum and maximum bounds (### verify) - - This function helps to ensure that by the following rules (in the following order): - 1. If minimum > maximum, set minimum = maximum - 2. Make sure preferred is not outside the [minimum,maximum] range. - 3. If descent > minimum, set descent = minimum (### verify if this is correct, it might - need some refinements to multiline texts) - - If any values are "not set" (i.e. negative), they will be left untouched, so that we - know which values needs to be fetched from the implicit hints (not user hints). - */ -static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent) -{ - if (minimum >= 0 && maximum >= 0 && minimum > maximum) - minimum = maximum; - - if (preferred >= 0) { - if (minimum >= 0 && preferred < minimum) { - preferred = minimum; - } else if (maximum >= 0 && preferred > maximum) { - preferred = maximum; - } - } - - if (minimum >= 0 && descent > minimum) - descent = minimum; -} - -static void boundSize(QSizeF &result, const QSizeF &size) -{ - if (size.width() >= 0 && size.width() < result.width()) - result.setWidth(size.width()); - if (size.height() >= 0 && size.height() < result.height()) - result.setHeight(size.height()); -} - -static void expandSize(QSizeF &result, const QSizeF &size) -{ - if (size.width() >= 0 && size.width() > result.width()) - result.setWidth(size.width()); - if (size.height() >= 0 && size.height() > result.height()) - result.setHeight(size.height()); -} - -static inline void combineHints(qreal ¤t, qreal fallbackHint) -{ - if (current < 0) - current = fallbackHint; -} - -static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize) -{ - combineHints(result.rwidth(), fallbackSize.width()); - combineHints(result.rheight(), fallbackSize.height()); -} - -static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size) -{ - if (!info) return; - - Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize); - - const QSizeF constraint(which == Qt::MinimumSize - ? QSizeF(info->minimumWidth(), info->minimumHeight()) - : QSizeF(info->maximumWidth(), info->maximumHeight())); - - if (!info->isExtentExplicitlySet(Qt::Horizontal, which)) - combineHints(size->rwidth(), constraint.width()); - if (!info->isExtentExplicitlySet(Qt::Vertical, which)) - combineHints(size->rheight(), constraint.height()); -} - -/*! - \internal - Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo. - - It is like this is because it enables it to be reused. - - The goal of this function is to return the effective minimum, preferred and maximum size hints - that the layout will use for this item. - This function takes care of gathering all explicitly set size hints, normalizes them so - that min < pref < max. - Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints, - which is usually derived from the content of the layouts (or items). - - The following table illustrates the preference of the properties used for measuring layout - items. If present, the USER properties will be preferred. If USER properties are not present, - the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an - ultimate fallback. - - Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been - explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This - determines if it should be used as a USER or as a HINT value. - - Fractional size hints will be ceiled to the closest integer. This is in order to give some - slack when the items are snapped to the pixel grid. - - | *Minimum* | *Preferred* | *Maximum* | -+----------------+----------------------+-----------------------+--------------------------+ -|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth | -|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth | -|FALLBACK | 0 | width | Number.POSITIVE_INFINITY | -+----------------+----------------------+-----------------------+--------------------------+ - */ -void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight) -{ - for (int i = 0; i < Qt::NSizeHints; ++i) - cachedSizeHints[i] = QSizeF(); - QQuickLayoutAttached *info = attachedLayoutObject(item, false); - // First, retrieve the user-specified hints from the attached "Layout." properties - if (info) { - struct Getters { - SizeGetter call[NSizes]; - }; - - static Getters horGetters = { - {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth}, - }; - - static Getters verGetters = { - {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight} - }; - for (int i = 0; i < NSizes; ++i) { - SizeGetter getter = horGetters.call[i]; - Q_ASSERT(getter); - - if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i)) - cachedSizeHints[i].setWidth(qCeil((info->*getter)())); - - getter = verGetters.call[i]; - Q_ASSERT(getter); - if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i)) - cachedSizeHints[i].setHeight(qCeil((info->*getter)())); - } - } - - QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; - QSizeF &prefS = cachedSizeHints[Qt::PreferredSize]; - QSizeF &maxS = cachedSizeHints[Qt::MaximumSize]; - QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent]; - - // For instance, will normalize the following user-set hints - // from: [10, 5, 60] - // to: [10, 10, 60] - normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); - normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); - - // All explicit values gathered, now continue to gather the implicit sizes - - //--- GATHER MAXIMUM SIZE HINTS --- - combineImplicitHints(info, Qt::MaximumSize, &maxS); - combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity())); - // implicit max or min sizes should not limit an explicitly set preferred size - expandSize(maxS, prefS); - expandSize(maxS, minS); - - //--- GATHER MINIMUM SIZE HINTS --- - combineImplicitHints(info, Qt::MinimumSize, &minS); - expandSize(minS, QSizeF(0,0)); - boundSize(minS, prefS); - boundSize(minS, maxS); - - //--- GATHER PREFERRED SIZE HINTS --- - // First, from implicitWidth/Height - qreal &prefWidth = prefS.rwidth(); - qreal &prefHeight = prefS.rheight(); - if (prefWidth < 0 && item->implicitWidth() > 0) - prefWidth = qCeil(item->implicitWidth()); - if (prefHeight < 0 && item->implicitHeight() > 0) - prefHeight = qCeil(item->implicitHeight()); - - // If that fails, make an ultimate fallback to width/height - - if (!info && (prefWidth < 0 || prefHeight < 0)) - info = attachedLayoutObject(item); - - if (useFallbackToWidthOrHeight && info) { - /* This block is a bit hacky, but if we want to support using width/height - as preferred size hints in layouts, (which we think most people expect), - we only want to use the initial width. - This is because the width will change due to layout rearrangement, and the preferred - width should return the same value, regardless of the current width. - We therefore store the width in the implicitWidth attached property. - Since the layout listens to changes of implicitWidth, (it will - basically cause an invalidation of the layout), we have to disable that - notification while we set the implicit width (and height). - - Only use this fallback the first time the size hint is queried. Otherwise, we might - end up picking a width that is different than what was specified in the QML. - */ - if (prefWidth < 0 || prefHeight < 0) { - item->blockSignals(true); - if (prefWidth < 0) { - prefWidth = item->width(); - item->setImplicitWidth(prefWidth); - } - if (prefHeight < 0) { - prefHeight = item->height(); - item->setImplicitHeight(prefHeight); - } - item->blockSignals(false); - } - } - - - - // Normalize again after the implicit hints have been gathered - expandSize(prefS, minS); - boundSize(prefS, maxS); - - //--- GATHER DESCENT - // Minimum descent is only applicable for the effective minimum height, - // so we gather the descent last. - const qreal minimumDescent = minS.height() - item->baselineOffset(); - descentS.setHeight(minimumDescent); - - if (info) { - QMarginsF margins = info->qMargins(); - QSizeF extraMargins(margins.left() + margins.right(), margins.top() + margins.bottom()); - minS += extraMargins; - prefS += extraMargins; - maxS += extraMargins; - descentS += extraMargins; - } - if (attachedInfo) - *attachedInfo = info; -} - -/*! - \internal - - Assumes \a info is set (if the object has an attached property) - */ -QLayoutPolicy::Policy QQuickGridLayoutItem::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info) -{ - bool fillExtent = false; - bool isSet = false; - if (info) { - if (orientation == Qt::Horizontal) { - isSet = info->isFillWidthSet(); - if (isSet) fillExtent = info->fillWidth(); - } else { - isSet = info->isFillHeightSet(); - if (isSet) fillExtent = info->fillHeight(); - } - } - if (!isSet && qobject_cast<QQuickLayout*>(item)) - fillExtent = true; - return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed; - -} - void QQuickGridLayoutEngine::setAlignment(QQuickItem *quickItem, Qt::Alignment alignment) { if (QQuickGridLayoutItem *item = findLayoutItem(quickItem)) { diff --git a/src/layouts/qquickgridlayoutengine_p.h b/src/layouts/qquickgridlayoutengine_p.h index a94ef934b..ce7285bf2 100644 --- a/src/layouts/qquickgridlayoutengine_p.h +++ b/src/layouts/qquickgridlayoutengine_p.h @@ -64,23 +64,18 @@ public: : QGridLayoutItem(row, column, rowSpan, columnSpan, alignment), m_item(item), sizeHintCacheDirty(true), useFallbackToWidthOrHeight(true) {} - typedef qreal (QQuickLayoutAttached::*SizeGetter)() const; - QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const { Q_UNUSED(constraint); // Quick Layouts does not support constraint atm return effectiveSizeHints()[which]; } - static void effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **info, bool useFallbackToWidthOrHeight); - static QLayoutPolicy::Policy effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info); - QSizeF *effectiveSizeHints() const { if (!sizeHintCacheDirty) return cachedSizeHints; - effectiveSizeHints_helper(m_item, cachedSizeHints, 0, useFallbackToWidthOrHeight); + QQuickLayout::effectiveSizeHints_helper(m_item, cachedSizeHints, 0, useFallbackToWidthOrHeight); useFallbackToWidthOrHeight = false; sizeHintCacheDirty = false; @@ -103,7 +98,7 @@ public: QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const { - return effectiveSizePolicy_helper(m_item, orientation, attachedLayoutObject(m_item, false)); + return QQuickLayout::effectiveSizePolicy_helper(m_item, orientation, attachedLayoutObject(m_item, false)); } void setGeometry(const QRectF &rect) @@ -112,8 +107,7 @@ public: const QRectF r = info ? rect.marginsRemoved(info->qMargins()) : rect; const QSizeF oldSize(m_item->width(), m_item->height()); const QSizeF newSize = r.size(); - QPointF topLeft(qCeil(r.x()), qCeil(r.y())); - m_item->setPosition(topLeft); + m_item->setPosition(r.topLeft()); if (newSize == oldSize) { if (QQuickLayout *lay = qobject_cast<QQuickLayout *>(m_item)) { if (lay->arrangementIsDirty()) @@ -135,7 +129,7 @@ private: class QQuickGridLayoutEngine : public QGridLayoutEngine { public: - QQuickGridLayoutEngine() : QGridLayoutEngine(Qt::AlignVCenter) { } + QQuickGridLayoutEngine() : QGridLayoutEngine(Qt::AlignVCenter, true /*snapToPixelGrid*/) { } int indexOf(QQuickItem *item) const { for (int i = 0; i < q_items.size(); ++i) { diff --git a/src/layouts/qquicklayout.cpp b/src/layouts/qquicklayout.cpp index 759ad6f25..ddf44b7b1 100644 --- a/src/layouts/qquicklayout.cpp +++ b/src/layouts/qquicklayout.cpp @@ -38,6 +38,7 @@ #include <QEvent> #include <QtCore/qcoreapplication.h> #include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> #include <limits> /*! @@ -50,7 +51,7 @@ An object of type Layout is attached to children of the layout to provide layout specific information about the item. - The properties of the attached object influences how the layout will arrange the items. + The properties of the attached object influence how the layout will arrange the items. For instance, you can specify \l minimumWidth, \l preferredWidth, and \l maximumWidth if the default values are not satisfactory. @@ -59,18 +60,18 @@ \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a \l{Layout::maximumWidth}{maximum size}. - If minimum size have not been explicitly specified on an item, the size is set to \c 0. - If maximum size have not been explicitly specified on an item, the size is set to + If minimum size has not been explicitly specified on an item, the size is set to \c 0. + If maximum size has not been explicitly specified on an item, the size is set to \c Number.POSITIVE_INFINITY. - For layouts, the implicit minimum and maximum size depends on the content of the layouts. + For layouts, the implicit minimum and maximum sizes depend on the content of the layouts. - The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If it is \c + The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If they are \c false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink between its minimum and maximum size as the layout is resized. \note It is not recommended to have bindings to the x, y, width, or height properties of items - in a layout, since this would conflict with the goal of the Layout, and also cause binding + in a layout, since this would conflict with the goals of Layout, and can also cause binding loops. @@ -116,10 +117,10 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent) \qmlattachedproperty real Layout::minimumWidth This property holds the minimum width of an item in a layout. - The default value is the items implicit minimum width. + The default value is the item's implicit minimum width. If the item is a layout, the implicit minimum width will be the minimum width the layout can - have without any of its items shrink beyond their minimum width. + have without any of its items shrinking below their minimum width. The implicit minimum width for any other item is \c 0. Setting this value to -1 will reset the width back to its implicit minimum width. @@ -144,10 +145,11 @@ void QQuickLayoutAttached::setMinimumWidth(qreal width) /*! \qmlattachedproperty real Layout::minimumHeight - The default value is the items implicit minimum height. + This property holds the minimum height of an item in a layout. + The default value is the item's implicit minimum height. If the item is a layout, the implicit minimum height will be the minimum height the layout can - have without any of its items shrink beyond their minimum height. + have without any of its items shrinking below their minimum height. The implicit minimum height for any other item is \c 0. Setting this value to -1 will reset the height back to its implicit minimum height. @@ -172,7 +174,7 @@ void QQuickLayoutAttached::setMinimumHeight(qreal height) \qmlattachedproperty real Layout::preferredWidth This property holds the preferred width of an item in a layout. - If the preferred width is -1 it will be ignored, and the layout + If the preferred width is \c -1 it will be ignored, and the layout will use \l{Item::implicitWidth}{implicitWidth} instead. The default is \c -1. @@ -193,7 +195,7 @@ void QQuickLayoutAttached::setPreferredWidth(qreal width) \qmlattachedproperty real Layout::preferredHeight This property holds the preferred height of an item in a layout. - If the preferred height is -1 it will be ignored, and the layout + If the preferred height is \c -1 it will be ignored, and the layout will use \l{Item::implicitHeight}{implicitHeight} instead. The default is \c -1. @@ -214,13 +216,13 @@ void QQuickLayoutAttached::setPreferredHeight(qreal height) \qmlattachedproperty real Layout::maximumWidth This property holds the maximum width of an item in a layout. - The default value is the items implicit maximum width. + The default value is the item's implicit maximum width. If the item is a layout, the implicit maximum width will be the maximum width the layout can - have without any of its items grow beyond their maximum width. + have without any of its items growing beyond their maximum width. The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY. - Setting this value to -1 will reset the width back to its implicit maximum width. + Setting this value to \c -1 will reset the width back to its implicit maximum width. \sa minimumWidth \sa preferredWidth @@ -241,13 +243,13 @@ void QQuickLayoutAttached::setMaximumWidth(qreal width) /*! \qmlattachedproperty real Layout::maximumHeight - The default value is the items implicit maximum height. + The default value is the item's implicit maximum height. If the item is a layout, the implicit maximum height will be the maximum height the layout can - have without any of its items grow beyond their maximum height. + have without any of its items growing beyond their maximum height. The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY. - Setting this value to -1 will reset the height back to its implicit maximum height. + Setting this value to \c -1 will reset the height back to its implicit maximum height. \sa minimumHeight \sa preferredHeight @@ -429,7 +431,7 @@ void QQuickLayoutAttached::setAlignment(Qt::Alignment align) \qmlattachedproperty real Layout::margins Sets the margins outside of an item to all have the same value. The item - itself does not evaluate its own margins. It is the parents responsibility + itself does not evaluate its own margins. It is the parent's responsibility to decide if it wants to evaluate the margins. Specifically, margins are only evaluated by ColumnLayout, RowLayout, @@ -440,12 +442,12 @@ void QQuickLayoutAttached::setAlignment(Qt::Alignment align) Therefore, if an item with margins is a child of another \c Item, its position, size and implicit size will remain unchanged. - Combining margins with alignment will align the item *including* its - margins. For instance, a vertically-centered Item with top margin 1 and - bottom margin 9 will cause the Items effective alignment within the cell to - be 4 pixels above the center. + Combining margins with alignment will align the item \e including its + margins. For instance, a vertically-centered Item with a top margin of \c 1 + and a bottom margin of \c 9 will cause the Items effective alignment within + the cell to be 4 pixels above the center. - The default value is 0 + The default value is \c 0. \sa leftMargin \sa topMargin @@ -684,9 +686,6 @@ QQuickItem *QQuickLayoutAttached::item() const } - - - QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) : QQuickItem(dd, parent), m_dirty(false) @@ -695,7 +694,7 @@ QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) QQuickLayout::~QQuickLayout() { - + d_func()->m_isReady = false; } QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object) @@ -710,7 +709,11 @@ void QQuickLayout::updatePolish() void QQuickLayout::componentComplete() { - QQuickItem::componentComplete(); + Q_D(QQuickLayout); + d->m_disableRearrange = true; + QQuickItem::componentComplete(); // will call our geometryChanged(), (where isComponentComplete() == true) + d->m_disableRearrange = false; + d->m_isReady = true; } void QQuickLayout::invalidate(QQuickItem * /*childItem*/) @@ -726,9 +729,337 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/) } } +bool QQuickLayout::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const +{ + Q_D(const QQuickLayout); + bool ignoreItem = true; + QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); + if (childPrivate->explicitVisible) { + effectiveSizeHints_helper(child, sizeHints, &info, true); + QSizeF effectiveMaxSize = sizeHints[Qt::MaximumSize]; + if (!effectiveMaxSize.isNull()) { + QSizeF &prefS = sizeHints[Qt::PreferredSize]; + if (effectiveSizePolicy_helper(child, Qt::Horizontal, info) == QLayoutPolicy::Fixed) + effectiveMaxSize.setWidth(prefS.width()); + if (effectiveSizePolicy_helper(child, Qt::Vertical, info) == QLayoutPolicy::Fixed) + effectiveMaxSize.setHeight(prefS.height()); + } + ignoreItem = effectiveMaxSize.isNull(); + } + + if (ignoreItem) + d->m_ignoredItems << child; + return ignoreItem; +} + +void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (change == ItemChildAddedChange) { + QQuickItem *item = value.item; + QObject::connect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); + QObject::connect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); + QObject::connect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); + if (isReady()) + updateLayoutItems(); + } else if (change == ItemChildRemovedChange) { + QQuickItem *item = value.item; + QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); + QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); + QObject::disconnect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); + if (isReady()) + updateLayoutItems(); + } + QQuickItem::itemChange(change, value); +} + +void QQuickLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickLayout); + QQuickItem::geometryChanged(newGeometry, oldGeometry); + if (d->m_disableRearrange || !isReady() || !newGeometry.isValid()) + return; + + quickLayoutDebug() << "QQuickStackLayout::geometryChanged" << newGeometry << oldGeometry; + rearrange(newGeometry.size()); +} + +void QQuickLayout::invalidateSenderItem() +{ + if (!isReady()) + return; + QQuickItem *item = static_cast<QQuickItem *>(sender()); + Q_ASSERT(item); + invalidate(item); +} + +bool QQuickLayout::isReady() const +{ + return d_func()->m_isReady; +} + void QQuickLayout::rearrange(const QSizeF &/*size*/) { m_dirty = false; } + +/* + The layout engine assumes: + 1. minimum <= preferred <= maximum + 2. descent is within minimum and maximum bounds (### verify) + + This function helps to ensure that by the following rules (in the following order): + 1. If minimum > maximum, set minimum = maximum + 2. Clamp preferred to be between the [minimum,maximum] range. + 3. If descent > minimum, set descent = minimum (### verify if this is correct, it might + need some refinements to multiline texts) + + If any values are "not set" (i.e. negative), they will be left untouched, so that we + know which values needs to be fetched from the implicit hints (not user hints). + */ +static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent) +{ + if (minimum >= 0 && maximum >= 0 && minimum > maximum) + minimum = maximum; + + if (preferred >= 0) { + if (minimum >= 0 && preferred < minimum) { + preferred = minimum; + } else if (maximum >= 0 && preferred > maximum) { + preferred = maximum; + } + } + + if (minimum >= 0 && descent > minimum) + descent = minimum; +} + +static void boundSize(QSizeF &result, const QSizeF &size) +{ + if (size.width() >= 0 && size.width() < result.width()) + result.setWidth(size.width()); + if (size.height() >= 0 && size.height() < result.height()) + result.setHeight(size.height()); +} + +static void expandSize(QSizeF &result, const QSizeF &size) +{ + if (size.width() >= 0 && size.width() > result.width()) + result.setWidth(size.width()); + if (size.height() >= 0 && size.height() > result.height()) + result.setHeight(size.height()); +} + +static inline void combineHints(qreal ¤t, qreal fallbackHint) +{ + if (current < 0) + current = fallbackHint; +} + +static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize) +{ + combineHints(result.rwidth(), fallbackSize.width()); + combineHints(result.rheight(), fallbackSize.height()); +} + +static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size) +{ + if (!info) return; + + Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize); + + const QSizeF constraint(which == Qt::MinimumSize + ? QSizeF(info->minimumWidth(), info->minimumHeight()) + : QSizeF(info->maximumWidth(), info->maximumHeight())); + + if (!info->isExtentExplicitlySet(Qt::Horizontal, which)) + combineHints(size->rwidth(), constraint.width()); + if (!info->isExtentExplicitlySet(Qt::Vertical, which)) + combineHints(size->rheight(), constraint.height()); +} + +typedef qreal (QQuickLayoutAttached::*SizeGetter)() const; + +/*! + \internal + Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo. + + It is like this is because it enables it to be reused. + + The goal of this function is to return the effective minimum, preferred and maximum size hints + that the layout will use for this item. + This function takes care of gathering all explicitly set size hints, normalizes them so + that min < pref < max. + Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints, + which is usually derived from the content of the layouts (or items). + + The following table illustrates the preference of the properties used for measuring layout + items. If present, the USER properties will be preferred. If USER properties are not present, + the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an + ultimate fallback. + + Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been + explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This + determines if it should be used as a USER or as a HINT value. + + Fractional size hints will be ceiled to the closest integer. This is in order to give some + slack when the items are snapped to the pixel grid. + + | *Minimum* | *Preferred* | *Maximum* | ++----------------+----------------------+-----------------------+--------------------------+ +|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth | +|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth | +|FALLBACK | 0 | width | Number.POSITIVE_INFINITY | ++----------------+----------------------+-----------------------+--------------------------+ + */ +void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight) +{ + for (int i = 0; i < Qt::NSizeHints; ++i) + cachedSizeHints[i] = QSizeF(); + QQuickLayoutAttached *info = attachedLayoutObject(item, false); + // First, retrieve the user-specified hints from the attached "Layout." properties + if (info) { + struct Getters { + SizeGetter call[NSizes]; + }; + + static Getters horGetters = { + {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth}, + }; + + static Getters verGetters = { + {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight} + }; + for (int i = 0; i < NSizes; ++i) { + SizeGetter getter = horGetters.call[i]; + Q_ASSERT(getter); + + if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i)) + cachedSizeHints[i].setWidth((info->*getter)()); + + getter = verGetters.call[i]; + Q_ASSERT(getter); + if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i)) + cachedSizeHints[i].setHeight((info->*getter)()); + } + } + + QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; + QSizeF &prefS = cachedSizeHints[Qt::PreferredSize]; + QSizeF &maxS = cachedSizeHints[Qt::MaximumSize]; + QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent]; + + // For instance, will normalize the following user-set hints + // from: [10, 5, 60] + // to: [10, 10, 60] + normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); + normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); + + // All explicit values gathered, now continue to gather the implicit sizes + + //--- GATHER MAXIMUM SIZE HINTS --- + combineImplicitHints(info, Qt::MaximumSize, &maxS); + combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity())); + // implicit max or min sizes should not limit an explicitly set preferred size + expandSize(maxS, prefS); + expandSize(maxS, minS); + + //--- GATHER MINIMUM SIZE HINTS --- + combineImplicitHints(info, Qt::MinimumSize, &minS); + expandSize(minS, QSizeF(0,0)); + boundSize(minS, prefS); + boundSize(minS, maxS); + + //--- GATHER PREFERRED SIZE HINTS --- + // First, from implicitWidth/Height + qreal &prefWidth = prefS.rwidth(); + qreal &prefHeight = prefS.rheight(); + if (prefWidth < 0 && item->implicitWidth() > 0) + prefWidth = qCeil(item->implicitWidth()); + if (prefHeight < 0 && item->implicitHeight() > 0) + prefHeight = qCeil(item->implicitHeight()); + + // If that fails, make an ultimate fallback to width/height + + if (!info && (prefWidth < 0 || prefHeight < 0)) + info = attachedLayoutObject(item); + + if (useFallbackToWidthOrHeight && info) { + /* This block is a bit hacky, but if we want to support using width/height + as preferred size hints in layouts, (which we think most people expect), + we only want to use the initial width. + This is because the width will change due to layout rearrangement, and the preferred + width should return the same value, regardless of the current width. + We therefore store the width in the implicitWidth attached property. + Since the layout listens to changes of implicitWidth, (it will + basically cause an invalidation of the layout), we have to disable that + notification while we set the implicit width (and height). + + Only use this fallback the first time the size hint is queried. Otherwise, we might + end up picking a width that is different than what was specified in the QML. + */ + if (prefWidth < 0 || prefHeight < 0) { + item->blockSignals(true); + if (prefWidth < 0) { + prefWidth = item->width(); + item->setImplicitWidth(prefWidth); + } + if (prefHeight < 0) { + prefHeight = item->height(); + item->setImplicitHeight(prefHeight); + } + item->blockSignals(false); + } + } + + + + // Normalize again after the implicit hints have been gathered + expandSize(prefS, minS); + boundSize(prefS, maxS); + + //--- GATHER DESCENT + // Minimum descent is only applicable for the effective minimum height, + // so we gather the descent last. + const qreal minimumDescent = minS.height() - item->baselineOffset(); + descentS.setHeight(minimumDescent); + + if (info) { + QMarginsF margins = info->qMargins(); + QSizeF extraMargins(margins.left() + margins.right(), margins.top() + margins.bottom()); + minS += extraMargins; + prefS += extraMargins; + maxS += extraMargins; + descentS += extraMargins; + } + if (attachedInfo) + *attachedInfo = info; +} + +/*! + \internal + + Assumes \a info is set (if the object has an attached property) + */ +QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info) +{ + bool fillExtent = false; + bool isSet = false; + if (info) { + if (orientation == Qt::Horizontal) { + isSet = info->isFillWidthSet(); + if (isSet) fillExtent = info->fillWidth(); + } else { + isSet = info->isFillHeightSet(); + if (isSet) fillExtent = info->fillHeight(); + } + } + if (!isSet && qobject_cast<QQuickLayout*>(item)) + fillExtent = true; + return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed; + +} + + + QT_END_NAMESPACE diff --git a/src/layouts/qquicklayout_p.h b/src/layouts/qquicklayout_p.h index 37f6ca009..d613f5bd6 100644 --- a/src/layouts/qquicklayout_p.h +++ b/src/layouts/qquicklayout_p.h @@ -40,6 +40,7 @@ #include <QPointer> #include <QQuickItem> #include <private/qquickitem_p.h> +#include <QtGui/private/qlayoutpolicy_p.h> QT_BEGIN_NAMESPACE @@ -81,6 +82,16 @@ public: virtual void rearrange(const QSizeF &); bool arrangementIsDirty() const { return m_dirty; } + + static void effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **info, bool useFallbackToWidthOrHeight); + static QLayoutPolicy::Policy effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info); + bool shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const; + + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + bool isReady() const; + + protected: void updatePolish() Q_DECL_OVERRIDE; @@ -90,6 +101,9 @@ protected: NOrientations }; +protected slots: + void invalidateSenderItem(); + private: bool m_dirty; @@ -102,6 +116,13 @@ private: class QQuickLayoutPrivate : public QQuickItemPrivate { Q_DECLARE_PUBLIC(QQuickLayout) +public: + QQuickLayoutPrivate() : m_isReady(false), m_disableRearrange(true) {} + +protected: + unsigned m_isReady : 1; + unsigned m_disableRearrange : 1; + mutable QSet<QQuickItem *> m_ignoredItems; }; diff --git a/src/layouts/qquicklinearlayout.cpp b/src/layouts/qquicklinearlayout.cpp index 0b9c6f546..78cc635ca 100644 --- a/src/layouts/qquicklinearlayout.cpp +++ b/src/layouts/qquicklinearlayout.cpp @@ -323,7 +323,6 @@ void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignmen QQuickGridLayoutBase::~QQuickGridLayoutBase() { Q_D(QQuickGridLayoutBase); - d->m_isReady = false; /* Avoid messy deconstruction, should give: * Faster deconstruction @@ -341,12 +340,8 @@ QQuickGridLayoutBase::~QQuickGridLayoutBase() void QQuickGridLayoutBase::componentComplete() { - Q_D(QQuickGridLayoutBase); quickLayoutDebug() << objectName() << "QQuickGridLayoutBase::componentComplete()" << parent(); - d->m_disableRearrange = true; - QQuickLayout::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true) - d->m_isReady = true; - d->m_disableRearrange = false; + QQuickLayout::componentComplete(); updateLayoutItems(); QQuickItem *par = parentItem(); @@ -469,37 +464,16 @@ void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &v QQuickItem *item = value.item; QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); QObject::connect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged())); - QObject::connect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); - QObject::connect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); - QObject::connect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); - - if (isReady()) - updateLayoutItems(); } else if (change == ItemChildRemovedChange) { quickLayoutDebug() << "ItemChildRemovedChange"; QQuickItem *item = value.item; QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged())); - QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); - QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); - QObject::disconnect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); - if (isReady()) - updateLayoutItems(); } QQuickLayout::itemChange(change, value); } -void QQuickGridLayoutBase::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - Q_D(QQuickGridLayoutBase); - QQuickLayout::geometryChanged(newGeometry, oldGeometry); - if (d->m_disableRearrange || !isReady() || !newGeometry.isValid()) - return; - quickLayoutDebug() << "QQuickGridLayoutBase::geometryChanged" << newGeometry << oldGeometry; - rearrange(newGeometry.size()); -} - void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem) { Q_D(QQuickGridLayoutBase); @@ -508,11 +482,6 @@ void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem) d->engine.removeRows(index, 1, d->orientation); } -bool QQuickGridLayoutBase::isReady() const -{ - return d_func()->m_isReady; -} - void QQuickGridLayoutBase::onItemVisibleChanged() { if (!isReady()) @@ -535,15 +504,6 @@ void QQuickGridLayoutBase::onItemDestroyed() } } -void QQuickGridLayoutBase::invalidateSenderItem() -{ - if (!isReady()) - return; - QQuickItem *item = static_cast<QQuickItem *>(sender()); - Q_ASSERT(item); - invalidate(item); -} - void QQuickGridLayoutBase::rearrange(const QSizeF &size) { Q_D(QQuickGridLayoutBase); @@ -578,29 +538,6 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size) } } -bool QQuickGridLayoutBase::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) -{ - Q_D(QQuickGridLayoutBase); - bool ignoreItem = true; - QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); - if (childPrivate->explicitVisible) { - QQuickGridLayoutItem::effectiveSizeHints_helper(child, sizeHints, &info, true); - QSizeF effectiveMaxSize = sizeHints[Qt::MaximumSize]; - if (!effectiveMaxSize.isNull()) { - QSizeF &prefS = sizeHints[Qt::PreferredSize]; - if (QQuickGridLayoutItem::effectiveSizePolicy_helper(child, Qt::Horizontal, info) == QLayoutPolicy::Fixed) - effectiveMaxSize.setWidth(prefS.width()); - if (QQuickGridLayoutItem::effectiveSizePolicy_helper(child, Qt::Vertical, info) == QLayoutPolicy::Fixed) - effectiveMaxSize.setHeight(prefS.height()); - } - ignoreItem = effectiveMaxSize.isNull(); - } - - if (ignoreItem) - d->m_ignoredItems << child; - return ignoreItem; -} - /********************************** ** ** QQuickGridLayout diff --git a/src/layouts/qquicklinearlayout_p.h b/src/layouts/qquicklinearlayout_p.h index b6483c4ed..e3522bced 100644 --- a/src/layouts/qquicklinearlayout_p.h +++ b/src/layouts/qquicklinearlayout_p.h @@ -39,7 +39,6 @@ #include "qquicklayout_p.h" #include "qquickgridlayoutengine_p.h" -#include <QtCore/qset.h> QT_BEGIN_NAMESPACE @@ -83,8 +82,6 @@ protected: void rearrange(const QSizeF &size) Q_DECL_OVERRIDE; virtual void insertLayoutItems() {} void itemChange(ItemChange change, const ItemChangeData &data) Q_DECL_OVERRIDE; - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; - bool shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints); signals: Q_REVISION(1) void layoutDirectionChanged(); @@ -92,11 +89,9 @@ signals: protected slots: void onItemVisibleChanged(); void onItemDestroyed(); - void invalidateSenderItem(); private: void removeGridItem(QGridLayoutItem *gridItem); - bool isReady() const; Q_DECLARE_PRIVATE(QQuickGridLayoutBase) }; @@ -107,9 +102,7 @@ class QQuickGridLayoutBasePrivate : public QQuickLayoutPrivate Q_DECLARE_PUBLIC(QQuickGridLayoutBase) public: - QQuickGridLayoutBasePrivate() : m_disableRearrange(true) - , m_isReady(false) - , m_rearranging(false) + QQuickGridLayoutBasePrivate() : m_rearranging(false) , m_updateAfterRearrange(false) , m_layoutDirection(Qt::LeftToRight) {} @@ -122,14 +115,11 @@ public: QQuickGridLayoutEngine engine; Qt::Orientation orientation; - unsigned m_disableRearrange : 1; - unsigned m_isReady : 1; unsigned m_rearranging : 1; unsigned m_updateAfterRearrange : 1; QVector<QQuickItem *> m_invalidateAfterRearrange; Qt::LayoutDirection m_layoutDirection : 2; - QSet<QQuickItem *> m_ignoredItems; QQuickLayoutStyleInfo *styleInfo; }; diff --git a/src/layouts/qquickstacklayout.cpp b/src/layouts/qquickstacklayout.cpp new file mode 100644 index 000000000..66513bfdc --- /dev/null +++ b/src/layouts/qquickstacklayout.cpp @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickstacklayout_p.h" +#include <limits> + +/*! + \qmltype StackLayout + \instantiates QQuickStackLayout + \inherits Item + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief The StackLayout class provides a stack of items where + only one item is visible at a time. + + The current visible item can be modified by setting the \l currentIndex property. + The index corresponds to the order of the StackLayout's children. + + In contrast to most other layouts, child Items' \l{Layout::fillWidth}{Layout.fillWidth} and \l{Layout::fillHeight}{Layout.fillHeight} properties + default to \c true. As a consequence, child items are by default filled to match the size of the StackLayout as long as their + \l{Layout::maximumWidth}{Layout.maximumWidth} or \l{Layout::maximumHeight}{Layout.maximumHeight} does not prevent it. + + Items are added to the layout by reparenting the item to the layout. Similarly, removal is done by reparenting the item from the layout. + Both of these operations will affect the layout's \l count property. + + The following code will create a StackLayout where only the 'plum' rectangle is visible. + \code + StackLayout { + id: layout + anchors.fill: parent + currentIndex: 1 + Rectangle { + color: 'teal' + implicitWidth: 200 + implicitHeight: 200 + } + Rectangle { + color: 'plum' + implicitWidth: 300 + implicitHeight: 200 + } + } + \endcode + + Items in a StackLayout support these attached properties: + \list + \li \l{Layout::minimumWidth}{Layout.minimumWidth} + \li \l{Layout::minimumHeight}{Layout.minimumHeight} + \li \l{Layout::preferredWidth}{Layout.preferredWidth} + \li \l{Layout::preferredHeight}{Layout.preferredHeight} + \li \l{Layout::maximumWidth}{Layout.maximumWidth} + \li \l{Layout::maximumHeight}{Layout.maximumHeight} + \li \l{Layout::fillWidth}{Layout.fillWidth} + \li \l{Layout::fillHeight}{Layout.fillHeight} + \endlist + + Read more about attached properties \l{QML Object Attributes}{here}. + \sa ColumnLayout + \sa GridLayout + \sa RowLayout + \sa StackView +*/ + +QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) : + QQuickLayout(*new QQuickStackLayoutPrivate, parent) +{ +} + +/*! + \qmlproperty int StackLayout::count + + This property holds the number of items that belong to the layout. + + Only items that are children of the StackLayout will be candidates for layouting. +*/ +int QQuickStackLayout::count() const +{ + Q_D(const QQuickStackLayout); + return d->count; +} + +/*! + \qmlproperty int StackLayout::currentIndex + + This property holds the index of the child item that is currently visible in the StackLayout. + By default it will be \c -1 for an empty layout, otherwise the default is \c 0 (referring to the first item). +*/ +int QQuickStackLayout::currentIndex() const +{ + Q_D(const QQuickStackLayout); + return d->currentIndex; +} + +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(); + } + } +} + +void QQuickStackLayout::componentComplete() +{ + QQuickLayout::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true) + + updateLayoutItems(); + + QQuickItem *par = parentItem(); + if (qobject_cast<QQuickLayout*>(par)) + return; + + rearrange(QSizeF(width(), height())); +} + +QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const +{ + QSizeF &askingFor = m_cachedSizeHints[whichSizeHint]; + if (!askingFor.isValid()) { + QSizeF &minS = m_cachedSizeHints[Qt::MinimumSize]; + QSizeF &prefS = m_cachedSizeHints[Qt::PreferredSize]; + QSizeF &maxS = m_cachedSizeHints[Qt::MaximumSize]; + + minS = QSizeF(0,0); + prefS = QSizeF(0,0); + maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()); + + const int count = itemCount(); + m_cachedItemSizeHints.resize(count); + for (int i = 0; i < count; ++i) { + SizeHints &hints = m_cachedItemSizeHints[i]; + QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array); + minS = minS.expandedTo(hints.min()); + prefS = prefS.expandedTo(hints.pref()); + //maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items. + // This is the same as QStackLayout does it. + // Not sure how descent makes sense here... + } + } + return askingFor; +} + +int QQuickStackLayout::indexOf(QQuickItem *childItem) const +{ + if (childItem) { + int indexOfItem = 0; + foreach (QQuickItem *item, childItems()) { + if (shouldIgnoreItem(item)) + continue; + if (childItem == item) + return indexOfItem; + ++indexOfItem; + } + } + return -1; +} + +QQuickItem *QQuickStackLayout::itemAt(int index) const +{ + foreach (QQuickItem *item, childItems()) { + if (shouldIgnoreItem(item)) + continue; + if (index == 0) + return item; + --index; + } + return 0; +} + +int QQuickStackLayout::itemCount() const +{ + int count = 0; + foreach (QQuickItem *item, childItems()) { + if (shouldIgnoreItem(item)) + continue; + ++count; + } + return count; +} + +void QQuickStackLayout::setAlignment(QQuickItem * /*item*/, Qt::Alignment /*align*/) +{ + // ### Do we have to respect alignment? +} + +void QQuickStackLayout::invalidate(QQuickItem *childItem) +{ + Q_D(QQuickStackLayout); + if (d->m_ignoredItems.contains(childItem)) { + // If an invalid item gets a valid size, it should be included, as it was added to the layout + updateLayoutItems(); + return; + } + + const int indexOfChild = indexOf(childItem); + if (indexOfChild >= 0 && indexOfChild < m_cachedItemSizeHints.count()) { + m_cachedItemSizeHints[indexOfChild].min() = QSizeF(); + m_cachedItemSizeHints[indexOfChild].pref() = QSizeF(); + m_cachedItemSizeHints[indexOfChild].max() = QSizeF(); + } + + for (int i = 0; i < Qt::NSizeHints; ++i) + m_cachedSizeHints[i] = QSizeF(); + QQuickLayout::invalidate(this); + + QQuickLayoutAttached *info = attachedLayoutObject(this); + + const QSizeF min = sizeHint(Qt::MinimumSize); + const QSizeF pref = sizeHint(Qt::PreferredSize); + const QSizeF max = sizeHint(Qt::MaximumSize); + + const bool old = info->setChangesNotificationEnabled(false); + info->setMinimumImplicitSize(min); + info->setMaximumImplicitSize(max); + info->setChangesNotificationEnabled(old); + if (pref.width() == implicitWidth() && pref.height() == implicitHeight()) { + // In case setImplicitSize does not emit implicit{Width|Height}Changed + if (QQuickLayout *parentLayout = qobject_cast<QQuickLayout *>(parentItem())) + parentLayout->invalidate(this); + } else { + setImplicitSize(pref.width(), pref.height()); + } +} + +void QQuickStackLayout::updateLayoutItems() +{ + Q_D(QQuickStackLayout); + d->m_ignoredItems.clear(); + const int count = itemCount(); + int oldIndex = d->currentIndex; + if (!d->explicitCurrentIndex) + d->currentIndex = (count > 0 ? 0 : -1); + + if (d->currentIndex != oldIndex) + emit currentIndexChanged(); + + if (count != d->count) { + d->count = count; + emit countChanged(); + } + for (int i = 0; i < count; ++i) + itemAt(i)->setVisible(d->currentIndex == i); + + invalidate(); +} + +void QQuickStackLayout::rearrange(const QSizeF &newSize) +{ + Q_D(QQuickStackLayout); + if (newSize.isNull() || !newSize.isValid()) + return; + (void)sizeHint(Qt::PreferredSize); // Make sure m_cachedItemSizeHints are valid + + if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count()) + return; + QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex]; + QQuickItem *item = itemAt(d->currentIndex); + Q_ASSERT(item); + item->setPosition(QPointF(0,0)); // ### respect alignment? + item->setSize(newSize.expandedTo(hints.min()).boundedTo(hints.max())); + QQuickLayout::rearrange(newSize); +} + +void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints) +{ + QQuickLayoutAttached *info = 0; + QQuickLayout::effectiveSizeHints_helper(item, sizeHints, &info, true); + if (!info) + return; + if (info->isFillWidthSet() && !info->fillWidth()) { + const qreal pref = sizeHints[Qt::PreferredSize].width(); + sizeHints[Qt::MinimumSize].setWidth(pref); + sizeHints[Qt::MaximumSize].setWidth(pref); + } + + if (info->isFillHeightSet() && !info->fillHeight()) { + const qreal pref = sizeHints[Qt::PreferredSize].height(); + sizeHints[Qt::MinimumSize].setHeight(pref); + sizeHints[Qt::MaximumSize].setHeight(pref); + } +} + +bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const +{ + const bool ignored = QQuickItemPrivate::get(item)->isTransparentForPositioner(); + if (ignored) + d_func()->m_ignoredItems << item; + return ignored; +} diff --git a/src/layouts/qquickstacklayout_p.h b/src/layouts/qquickstacklayout_p.h new file mode 100644 index 000000000..921214002 --- /dev/null +++ b/src/layouts/qquickstacklayout_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSTACKLAYOUT_H +#define QQUICKSTACKLAYOUT_H + +#include <qquicklayout_p.h> + +class QQuickStackLayoutPrivate; + +class QQuickStackLayout : public QQuickLayout +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + +public: + explicit QQuickStackLayout(QQuickItem *parent = 0); + int count() const; + int currentIndex() const; + void setCurrentIndex(int index); + + void componentComplete() Q_DECL_OVERRIDE; + QSizeF sizeHint(Qt::SizeHint whichSizeHint) const Q_DECL_OVERRIDE; + void setAlignment(QQuickItem *item, Qt::Alignment align) Q_DECL_OVERRIDE; + void invalidate(QQuickItem *childItem = 0) Q_DECL_OVERRIDE; + void updateLayoutItems() Q_DECL_OVERRIDE; + void rearrange(const QSizeF &) Q_DECL_OVERRIDE; + + // iterator + Q_INVOKABLE QQuickItem *itemAt(int index) const Q_DECL_OVERRIDE; + int itemCount() const Q_DECL_OVERRIDE; + int indexOf(QQuickItem *item) const; + + + +signals: + void currentIndexChanged(); + void countChanged(); + +public slots: + +private: + static void collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints); + bool shouldIgnoreItem(QQuickItem *item) const; + Q_DECLARE_PRIVATE(QQuickStackLayout) + + QList<QQuickItem*> m_items; + + typedef struct { + inline QSizeF &min() { return array[Qt::MinimumSize]; } + inline QSizeF &pref() { return array[Qt::PreferredSize]; } + inline QSizeF &max() { return array[Qt::MaximumSize]; } + QSizeF array[Qt::NSizeHints]; + } SizeHints; + + mutable QVector<SizeHints> m_cachedItemSizeHints; + mutable QSizeF m_cachedSizeHints[Qt::NSizeHints]; +}; + +class QQuickStackLayoutPrivate : public QQuickLayoutPrivate +{ + Q_DECLARE_PUBLIC(QQuickStackLayout) +public: + QQuickStackLayoutPrivate() : count(0), currentIndex(-1), explicitCurrentIndex(false) {} +private: + int count; + int currentIndex; + bool explicitCurrentIndex; +}; + +#endif // QQUICKSTACKLAYOUT_H diff --git a/src/widgets/qquickqfiledialog.cpp b/src/widgets/qquickqfiledialog.cpp index 90d1ef9e0..7ebebf1f0 100644 --- a/src/widgets/qquickqfiledialog.cpp +++ b/src/widgets/qquickqfiledialog.cpp @@ -209,6 +209,7 @@ void QFileDialogHelper::fileSelected(const QString& path) void QFileDialogHelper::filesSelected(const QStringList& paths) { QList<QUrl> pathUrls; + pathUrls.reserve(paths.count()); foreach (const QString &path, paths) pathUrls << QUrl::fromLocalFile(path); emit QPlatformFileDialogHelper::filesSelected(pathUrls); diff --git a/src/widgets/widgets.pro b/src/widgets/widgets.pro index 532083808..2e3c81642 100644 --- a/src/widgets/widgets.pro +++ b/src/widgets/widgets.pro @@ -1,3 +1,5 @@ +requires(contains(QT_CONFIG, accessibility)) + CXX_MODULE = qml TARGET = widgetsplugin TARGETPATH = QtQuick/PrivateWidgets |
