diff --git a/examples/galleryapp/resources.qrc b/examples/galleryapp/resources.qrc --- a/examples/galleryapp/resources.qrc +++ b/examples/galleryapp/resources.qrc @@ -16,6 +16,8 @@ ../gallerydata/contents/ui/gallery/TabBarGallery.qml ../gallerydata/contents/ui/gallery/TextFieldGallery.qml ../gallerydata/contents/ui/gallery/ColorsGallery.qml + ../gallerydata/contents/ui/gallery/MetricsGallery.qml + ../gallerydata/contents/ui/gallery/LayersGallery.qml ../gallerydata/contents/ui/ExampleApp.qml ../gallerydata/contents/ui/DesktopExampleApp.qml ../gallerydata/metadata.desktop diff --git a/examples/gallerydata/contents/ui/DesktopExampleApp.qml b/examples/gallerydata/contents/ui/DesktopExampleApp.qml --- a/examples/gallerydata/contents/ui/DesktopExampleApp.qml +++ b/examples/gallerydata/contents/ui/DesktopExampleApp.qml @@ -64,16 +64,16 @@ }, Kirigami.Action { text: "Checkable" - iconName: "view-list-details" + iconName: "go-next" checkable: true checked: false onTriggered: { showPassiveNotification("Action checked: " + checked) } }, Kirigami.Action { text: "Open A Page" - iconName: "configure" + iconName: "view-list-details" checkable: true //Need to do this, otherwise it breaks the bindings property bool current: pageStack.currentItem ? pageStack.currentItem.objectName == "settingsPage" : false @@ -83,6 +83,13 @@ onTriggered: { pageStack.push(settingsComponent); } + }, + Kirigami.Action { + text: "Open A Layer" + iconName: "configure" + onTriggered: { + pageStack.layers.push(Qt.resolvedUrl("gallery/LayersGallery.qml")); + } } ] diff --git a/examples/gallerydata/contents/ui/ExampleApp.qml b/examples/gallerydata/contents/ui/ExampleApp.qml --- a/examples/gallerydata/contents/ui/ExampleApp.qml +++ b/examples/gallerydata/contents/ui/ExampleApp.qml @@ -64,16 +64,16 @@ }, Kirigami.Action { text: "Checkable" - iconName: "view-list-details" + iconName: "go-next" checkable: true checked: false onTriggered: { showPassiveNotification("Action checked: " + checked) } }, Kirigami.Action { text: "Open A Page" - iconName: "configure" + iconName: "view-list-details" checkable: true //Need to do this, otherwise it breaks the bindings property bool current: pageStack.currentItem ? pageStack.currentItem.objectName == "settingsPage" : false @@ -83,6 +83,13 @@ onTriggered: { pageStack.push(settingsComponent); } + }, + Kirigami.Action { + text: "Open A Layer" + iconName: "configure" + onTriggered: { + pageStack.layers.push(Qt.resolvedUrl("gallery/LayersGallery.qml")); + } } ] diff --git a/examples/gallerydata/contents/ui/gallery/LayersGallery.qml b/examples/gallerydata/contents/ui/gallery/LayersGallery.qml new file mode 100644 --- /dev/null +++ b/examples/gallerydata/contents/ui/gallery/LayersGallery.qml @@ -0,0 +1,85 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.0 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.0 + +ScrollablePage { + id: page + Layout.fillWidth: true + //implicitWidth: Units.gridUnit * (Math.floor(Math.random() * 35) + 8) + + title: "Multiple Columns" + + actions { + main: Action { + iconName: "document-edit" + text: "Main Action Text" + onTriggered: { + showPassiveNotification("Action button in buttons page clicked"); + } + } + left: Action { + iconName: "go-previous" + text: "Left Action Text" + onTriggered: { + showPassiveNotification("Left action triggered") + } + } + contextualActions: [ + Action { + text:"Action 1" + iconName: "go-next" + onTriggered: showPassiveNotification("Action 1 clicked") + }, + Action { + text:"Action 2" + iconName: "folder" + enabled: false + onTriggered: showPassiveNotification("Action 2 clicked") + } + ] + } + + ColumnLayout { + width: page.width + spacing: Units.smallSpacing + + Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: "This page is used to test multiple layers: it will cover all the columns" + } + + Controls.Button { + text: "Push A New Layer" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: pageStack.layers.push(Qt.resolvedUrl("LayersGallery.qml")); + } + Controls.Button { + text: "Pop A Layer" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: pageStack.layers.pop(); + } + } + + +} diff --git a/src/controls/ContextDrawer.qml b/src/controls/ContextDrawer.qml --- a/src/controls/ContextDrawer.qml +++ b/src/controls/ContextDrawer.qml @@ -81,7 +81,9 @@ * This can be any type of object that a ListView can accept as model. * It expects items compatible with either QAction or Kirigami Action */ - property var actions: pageStack.currentItem ? pageStack.currentItem.contextualActions : null + property var actions: pageStack.layers.depth > 1 + ? pageStack.layers.currentItem.contextualActions + : (pageStack.currentItem ? pageStack.currentItem.contextualActions : null) enabled: menu.count > 0 edge: Qt.RightEdge drawerOpen: false @@ -93,14 +95,6 @@ handleVisible: applicationWindow == undefined || applicationWindow().wideScreen == true ? false : applicationWindow().controlsVisible - Connections { - target: pageStack - onCurrentItemChanged: { - if (pageStack.currentItem) - actions = pageStack.currentItem.contextualActions - } - } - contentItem: ScrollView { implicitWidth: Units.gridUnit * 20 ListView { diff --git a/src/controls/Page.qml b/src/controls/Page.qml --- a/src/controls/Page.qml +++ b/src/controls/Page.qml @@ -256,7 +256,7 @@ } height: item ? item.height : 0 source: (applicationWindow().header && applicationWindow().header.toString().indexOf("ToolBarApplicationHeader") === 0) || - (applicationWindow().footer && applicationWindow().footer.toString().indexOf("ToolBarApplicationHeader") === 0) + (applicationWindow().footer && applicationWindow().footer.visible && applicationWindow().footer.toString().indexOf("ToolBarApplicationHeader") === 0) ? "" : Qt.resolvedUrl("./private/ActionButton.qml") } diff --git a/src/controls/PageRow.qml b/src/controls/PageRow.qml --- a/src/controls/PageRow.qml +++ b/src/controls/PageRow.qml @@ -21,6 +21,7 @@ import QtQuick.Layouts 1.2 import QtQml.Models 2.2 import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.0 as QQC2 import org.kde.kirigami 2.0 /** @@ -297,6 +298,14 @@ } } + /** + * layers: QtQuick.Controls.PageStack + * Access to the modal layers. + * Sometimes an application needs a modal page that always covers all the rows. + * For instance the full screen image of an image viewer or a settings page. + * @since 5.38 + */ + property alias layers: layersStack //END FUNCTIONS onInitialPageChanged: { @@ -323,9 +332,21 @@ script: mainView.flick(100, 0) } } + QQC2.StackView { + id: layersStack + z: 99 + anchors.fill: parent + initialItem: mainView + function clear () { + //don't let it kill the main page row + var d = root.depth; + for (var i = 1; i < d; ++i) { + pop(); + } + } + } ListView { id: mainView - z: 99 anchors.fill: parent boundsBehavior: Flickable.StopAtBounds orientation: Qt.Horizontal diff --git a/src/controls/private/ActionButton.qml b/src/controls/private/ActionButton.qml --- a/src/controls/private/ActionButton.qml +++ b/src/controls/private/ActionButton.qml @@ -42,6 +42,13 @@ transform: Translate { id: translateTransform + y: mouseArea.internalVisibility ? 0 : button.height + Behavior on y { + NumberAnimation { + duration: Units.longDuration + easing.type: mouseArea.internalVisibility == true ? Easing.InQuad : Easing.OutQuad + } + } } Item { @@ -78,15 +85,6 @@ visible: action != null || leftAction != null || rightAction != null property bool internalVisibility: (applicationWindow === undefined || (applicationWindow().controlsVisible && applicationWindow().height > root.height*2)) && (root.action === null || root.action.visible === undefined || root.action.visible) preventStealing: true - onInternalVisibilityChanged: { - showAnimation.running = false; - if (internalVisibility) { - showAnimation.to = 0; - } else { - showAnimation.to = button.height; - } - showAnimation.running = true; - } drag { target: button @@ -213,13 +211,6 @@ } } - NumberAnimation { - id: showAnimation - target: translateTransform - properties: "y" - duration: Units.longDuration - easing.type: mouseArea.internalVisibility == true ? Easing.InQuad : Easing.OutQuad - } Item { id: background anchors { diff --git a/src/controls/templates/ApplicationHeader.qml b/src/controls/templates/ApplicationHeader.qml --- a/src/controls/templates/ApplicationHeader.qml +++ b/src/controls/templates/ApplicationHeader.qml @@ -18,6 +18,7 @@ */ import QtQuick 2.5 +import QtQuick.Controls 2.0 as QQC2 import QtQuick.Layouts 1.2 import "private" import org.kde.kirigami 2.0 @@ -56,10 +57,10 @@ property bool backButtonEnabled: (!titleList.isTabBar && (!Settings.isMobile || Qt.platform.os == "ios")) onBackButtonEnabledChanged: { - if (backButtonEnabled) { + if (backButtonEnabled && !titleList.backButton) { var component = Qt.createComponent(Qt.resolvedUrl("private/BackButton.qml")); titleList.backButton = component.createObject(titleList.parent); - } else { + } else if (titleList.backButton) { titleList.backButton.destroy(); } } @@ -92,7 +93,7 @@ elide: Text.ElideRight text: page ? page.title : "" font.pixelSize: titleList.height / 1.6 - height: parent.height + verticalAlignment: Text.AlignVCenter Rectangle { anchors { bottom: parent.bottom @@ -120,6 +121,23 @@ opacity: 0.4 } + QQC2.StackView { + id: stack + anchors { + fill: parent + leftMargin: titleList.scrollingLocked && titleList.wideMode ? 0 : titleList.backButton.width + } + initialItem: titleList + } + Repeater { + model: __appWindow.pageStack.layers.depth -1 + delegate: Loader { + sourceComponent: header.pageDelegate + readonly property Page page: __appWindow.pageStack.layers.get(modelData+1) + Component.onCompleted: stack.push(this) + Component.onDestruction: stack.pop() + } + } ListView { id: titleList readonly property bool wideMode: typeof __appWindow.pageStack.wideMode !== "undefined" ? __appWindow.pageStack.wideMode : titleList.wideMode @@ -129,19 +147,10 @@ //uses this to have less strings comparisons property bool scrollMutex property bool isTabBar: header.headerStyle == ApplicationHeaderStyle.TabBar - Component.onCompleted: { - //only iOS and desktop systems put the back button on top left corner - if (header.backButtonEnabled) { - var component = Qt.createComponent(Qt.resolvedUrl("private/BackButton.qml")); - titleList.backButton = component.createObject(titleList.parent); - } - } + property Item backButton clip: true - anchors { - fill: parent - leftMargin: titleList.scrollingLocked && titleList.wideMode ? 0 : backButton.width - } + cacheBuffer: width ? Math.max(0, width * count) : 0 displayMarginBeginning: __appWindow.pageStack.width * count orientation: ListView.Horizontal diff --git a/src/controls/templates/private/BackButton.qml b/src/controls/templates/private/BackButton.qml --- a/src/controls/templates/private/BackButton.qml +++ b/src/controls/templates/private/BackButton.qml @@ -29,7 +29,13 @@ implicitWidth: height visible: applicationWindow().pageStack.contentItem.contentWidth > applicationWindow().pageStack.contentItem.width z: 99 - onClicked: applicationWindow().pageStack.goBack(); + onClicked: { + if (applicationWindow().pageStack.layers && applicationWindow().pageStack.layers.depth > 1) { + applicationWindow().pageStack.layers.pop(); + } else { + applicationWindow().pageStack.goBack(); + } + } Icon { anchors.fill: parent opacity: parent.enabled ? 1 : 0.6