diff options
Diffstat (limited to 'src')
67 files changed, 1106 insertions, 422 deletions
diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 4c30664d..fa2d1b51 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 a2eff0b6..4e29dfe9 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 037fa550..d485cb65 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 444185cc..a16635ff 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 42abebe5..bca626e0 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 1756a296..346cd419 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 27635bc9..5fd21167 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 f4733cc5..4b965482 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 51abe758..a70e8407 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 a0b346c4..e3be2e44 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 c4e13729..8b8801fc 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 55850bf0..8483830b 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 1b99fd3e..6a4e8c6a 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 87b2808e..666fafc9 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 2297c365..3eefbe77 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 5c21848f..74d5ee7d 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/SplitView.qml b/src/controls/SplitView.qml index 41c50329..c2e361ac 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 26772781..c76459ff 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 c837c281..a1dacb21 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 f151a3ac..468d3587 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 973d09c0..c8d817c9 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 ed72951f..09bc7da3 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 4842c39a..94cc1240 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 678d365d..1da52227 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 e9247416..b5e024b4 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 b8f03f65..e90542fe 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 f5199f3f..1ead1b34 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 1901c40c..6424ed0e 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 3d39ce2b..8a87f809 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 f5d02cf3..07a4cd9e 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 bd043be9..f7a8324a 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 9bcdfe6d..3f5a8468 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 23360f06..87b13e0d 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 589869d3..0c8a0df6 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 48f62f16..f5d0a994 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 c97930f3..637c46c3 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 7dd176f0..f725b1ce 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 e8aa0422..33df123f 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.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.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 = qqcqmltypes qqcstylesqmltypes qqcexamples + +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.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 diff --git a/src/controls/doc/src/qtquickcontrols-overview.qdoc b/src/controls/doc/src/qtquickcontrols-overview.qdoc index 45a4557a..f549d0c8 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 15b99c18..a9c6d22a 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 fb186059..8188e955 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 94eb6fb4..792f064c 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 0b5012f1..c781f903 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 3f4508f4..e98b6cae 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 8ab956c6..e1afeef2 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 90a1fd67..6add916d 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 1828cc9e..e3b9c852 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 beabe65b..fec24189 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 a626179a..1c51fe71 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 be15a435..0702d398 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 a8f45167..59cfe22b 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 16031656..3524b9ef 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 b0b9db2d..9daaa6e6 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/plugin.cpp b/src/dialogs/plugin.cpp index 7fac166d..65740024 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/extras.pro b/src/extras/extras.pro index 2ebd8f81..4363ce00 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 3ef18f85..f7a73b7e 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 fa72fa8d..6a670539 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 553f45d0..2c08eec1 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 a94ef934..ce7285bf 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 759ad6f2..d812c112 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> /*! @@ -684,9 +685,6 @@ QQuickItem *QQuickLayoutAttached::item() const } - - - QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) : QQuickItem(dd, parent), m_dirty(false) @@ -695,7 +693,7 @@ QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) QQuickLayout::~QQuickLayout() { - + d_func()->m_isReady = false; } QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object) @@ -710,7 +708,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 +728,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 37f6ca00..d613f5bd 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 0b9c6f54..cbd32976 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,10 +464,6 @@ 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) { @@ -480,9 +471,6 @@ void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &v 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(); } @@ -490,16 +478,6 @@ void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &v 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 +486,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 +508,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 +542,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 b6483c4e..e3522bce 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 00000000..66513bfd --- /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 00000000..92121400 --- /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 90d1ef9e..7ebebf1f 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 53208380..2e3c8164 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 |