diff --git a/src/controls/ToolBarApplicationHeader.qml b/src/controls/ToolBarApplicationHeader.qml --- a/src/controls/ToolBarApplicationHeader.qml +++ b/src/controls/ToolBarApplicationHeader.qml @@ -39,78 +39,61 @@ pageDelegate: Item { id: delegateItem - readonly property Page page: applicationWindow().pageStack.get(modelData) - property ListView view: ListView.view readonly property bool current: __appWindow.pageStack.currentIndex == index property Row layout - width: { - //more columns shown? - if (__appWindow.wideScreen) { - if (modelData == 0 && view.x > 0) { - return page.width - view.x; - } else { - return page.width; - } - } else { - return Math.min(view.width, delegateRoot.implicitWidth + Units.smallSpacing); - } - } - height: view.height + implicitWidth: layout.width > 0 ? layout.width : heading.width + width: parent.width + height: parent.height - Component.onCompleted: { - layout = toolbarComponent.createObject(delegateItem) - } - Component { - id: toolbarComponent - Row { - id: layout - anchors.verticalCenter: parent.verticalCenter - x: __appWindow.wideScreen ? (Math.min(delegateItem.width - width, Math.max(0, delegateItem.view.contentX - delegateItem.x))) : 0 - spacing: 2 + Row { + id: layout + anchors.verticalCenter: parent.verticalCenter + spacing: 2 - Rectangle { - anchors.verticalCenter: parent.verticalCenter - color: Theme.textColor - opacity: 0.3 - width: Units.devicePixelRatio - height: parent.height * 0.6 - } - PrivateActionToolButton { - anchors.verticalCenter: parent.verticalCenter - action: page && page.actions ? page.actions.left : null - showText: false - } - PrivateActionToolButton { - anchors.verticalCenter: parent.verticalCenter - action: page && page.actions ? page.actions.main : null - showText: false - } - PrivateActionToolButton { - anchors.verticalCenter: parent.verticalCenter - action: page && page.actions ? page.actions.right : null - showText: false - } - Rectangle { + Rectangle { + anchors.verticalCenter: parent.verticalCenter + color: Theme.textColor + opacity: 0.3 + width: Units.devicePixelRatio + height: parent.height * 0.6 + } + PrivateActionToolButton { + anchors.verticalCenter: parent.verticalCenter + action: page && page.actions ? page.actions.left : null + showText: false + } + PrivateActionToolButton { + anchors.verticalCenter: parent.verticalCenter + action: page && page.actions ? page.actions.main : null + showText: false + } + PrivateActionToolButton { + anchors.verticalCenter: parent.verticalCenter + action: page && page.actions ? page.actions.right : null + showText: false + } + Rectangle { + anchors.verticalCenter: parent.verticalCenter + color: Theme.textColor + opacity: 0.3 + width: Units.devicePixelRatio + height: parent.height * 0.6 + visible: page && page.actions && (page.actions.left || page.actions.main || page.actions.right) + } + Repeater { + id: repeater + model: page && page.actions.contextualActions ? page.actions.contextualActions : null + delegate: PrivateActionToolButton { anchors.verticalCenter: parent.verticalCenter - color: Theme.textColor - opacity: 0.3 - width: Units.devicePixelRatio - height: parent.height * 0.6 - } - Repeater { - id: repeater - model: page && page.actions.contextualActions ? page.actions.contextualActions : null - delegate: PrivateActionToolButton { - anchors.verticalCenter: parent.verticalCenter - action: modelData - visible: modelData.visible && x+layout.x+width*2 < delegateItem.width - } + action: modelData + visible: modelData.visible && x+layout.x+width*2 < delegateItem.width } } } + Heading { - x: __appWindow.wideScreen ? (Math.min(delegateItem.width - width, Math.max(0, delegateItem.view.contentX - delegateItem.x))) : 0 + id: heading anchors.verticalCenter: parent.verticalCenter visible: layout.width <= 0 opacity: delegateItem.current ? 1 : 0.4 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 @@ -50,7 +50,47 @@ */ property int headerStyle: ApplicationHeaderStyle.Auto - property alias pageDelegate: titleList.delegate + property Component pageDelegate: Component { + Row { + height: parent.height + + spacing: Units.smallSpacing + + Icon { + //in tabbar mode this is just a spacer + visible: !__appWindow.wideScreen && (modelData > 0 || titleList.internalHeaderStyle == ApplicationHeaderStyle.TabBar) + height: title.height + width: height + selected: header.background && header.background.color && header.background.color == Theme.highlightColor + source: titleList.isTabBar ? "" : "go-next" + } + + Heading { + id: title + width:Math.min(titleList.width, implicitWidth) + anchors.verticalCenter: parent.verticalCenter + opacity: current ? 1 : 0.4 + //Scaling animate NativeRendering is too slow + renderType: Text.QtRendering + color: header.background && header.background.color && header.background.color == Theme.highlightColor ? Theme.highlightedTextColor : Theme.textColor + elide: Text.ElideRight + text: page ? page.title : "" + font.pixelSize: titleList.height / 1.6 + height: parent.height + Rectangle { + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: Units.smallSpacing + color: title.color + opacity: 0.6 + visible: titleList.isTabBar && current + } + } + } + } Rectangle { anchors { @@ -78,10 +118,7 @@ } property Item backButton clip: true - anchors { - fill: parent - leftMargin: (backButton ? backButton.width : (titleList.isTabBar ? 0 : Units.smallSpacing*2)) - } + anchors.fill: parent cacheBuffer: width ? Math.max(0, width * count) : 0 displayMarginBeginning: __appWindow.pageStack.width * count orientation: ListView.Horizontal @@ -134,7 +171,8 @@ } onMovementEnded: { if (__appWindow.wideScreen) { - __appWindow.pageStack.contentItem.movementEnded(); + //this will trigger snap as well + __appWindow.pageStack.contentItem.flick(0,0); } } @@ -149,22 +187,16 @@ delegate: MouseArea { id: delegate - readonly property Page page: __appWindow.pageStack.get(modelData) - //NOTE: why not use ListViewCurrentIndex? because listview itself resets - //currentIndex in some situations (since here we are using an int as a model, - //even more often) so the property binding gets broken - readonly property bool current: __appWindow.pageStack.currentIndex == index + readonly property int currentIndex: index + readonly property var currentModelData: modelData + clip: true width: { //more columns shown? - if (__appWindow.wideScreen && page) { - if (modelData == 0 && titleList.backButton) { - return page.width - titleList.backButton.width; - } else { - return page.width; - } + if (__appWindow.wideScreen && delegateLoader.page) { + return delegateLoader.page.width; } else { - return Math.min(titleList.width, delegateRoot.implicitWidth + Units.smallSpacing); + return Math.min(titleList.width, delegateLoader.implicitWidth + Units.smallSpacing); } } height: titleList.height @@ -184,46 +216,21 @@ } } - Row { - id: delegateRoot - x: Units.smallSpacing + __appWindow.wideScreen ? (Math.min(delegate.width - width, Math.max(0, titleList.contentX - delegate.x))) : 0 + Loader { + id: delegateLoader height: parent.height - - spacing: Units.smallSpacing - - Icon { - //in tabbar mode this is just a spacer - visible: !__appWindow.wideScreen && (modelData > 0 || titleList.internalHeaderStyle == ApplicationHeaderStyle.TabBar) - height: title.height - width: height - selected: header.background && header.background.color && header.background.color == Theme.highlightColor - source: titleList.isTabBar ? "" : "go-next" - } - - Heading { - id: title - width:Math.min(titleList.width, implicitWidth) - anchors.verticalCenter: parent.verticalCenter - opacity: delegate.current ? 1 : 0.4 - //Scaling animate NativeRendering is too slow - renderType: Text.QtRendering - color: header.background && header.background.color && header.background.color == Theme.highlightColor ? Theme.highlightedTextColor : Theme.textColor - elide: Text.ElideRight - text: page ? page.title : "" - font.pixelSize: titleList.height / 1.6 - height: parent.height - Rectangle { - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - height: Units.smallSpacing - color: title.color - opacity: 0.6 - visible: titleList.isTabBar && delegate.current - } - } + x: Units.smallSpacing + __appWindow.wideScreen ? (Math.min(delegate.width - implicitWidth, Math.max(0, titleList.contentX - delegate.x + (titleList.backButton ? titleList.backButton.width : 0)))) : 0 + width: parent.width - x + + sourceComponent: header.pageDelegate + + readonly property Page page: __appWindow.pageStack.get(modelData) + //NOTE: why not use ListViewCurrentIndex? because listview itself resets + //currentIndex in some situations (since here we are using an int as a model, + //even more often) so the property binding gets broken + readonly property bool current: __appWindow.pageStack.currentIndex == index + readonly property int index: parent.currentIndex + readonly property var modelData: parent.currentModelData } } Connections { diff --git a/src/controls/templates/private/PageRow.qml b/src/controls/templates/private/PageRow.qml --- a/src/controls/templates/private/PageRow.qml +++ b/src/controls/templates/private/PageRow.qml @@ -19,10 +19,11 @@ import QtQuick 2.5 import QtQuick.Layouts 1.2 +import QtQml.Models 2.2 import QtQuick.Templates 2.0 as T import org.kde.kirigami 2.0 -Item { +T.Control { id: root //BEGIN PROPERTIES @@ -39,12 +40,12 @@ /** * The currently visible Item */ - readonly property Item currentItem: mainFlickable.currentItem + readonly property Item currentItem: mainView.currentItem.page /** * the index of the currently visible Item */ - property alias currentIndex: mainFlickable.currentIndex + property alias currentIndex: mainView.currentIndex /** * The initial item when this PageRow is created @@ -54,7 +55,8 @@ /** * The main flickable of this Row */ - property alias contentItem: mainFlickable +// property alias contentItem: mainView + contentItem: mainView /** * The default width for a column @@ -71,7 +73,7 @@ * Otherwise the only way to go back will be programmatically * default: true */ - property alias interactive: mainFlickable.interactive +// property alias interactive: mainView.interactive //END PROPERTIES @@ -132,7 +134,7 @@ pagesLogic.append(container); container.visible = container.page.visible = true; - mainFlickable.currentIndex = container.level; + mainView.currentIndex = container.level; return container.page } @@ -200,195 +202,80 @@ //END FUNCTIONS - QtObject { - id: pagesLogic - - readonly property int count: mainLayout.children.length - property var componentCache - - property int roundedDefaultColumnWidth: root.width < root.defaultColumnWidth*2 ? root.width : root.defaultColumnWidth - - //NOTE:seems to only work if the array is defined in a declarative way, - //the Object in an imperative way, espacially on Android - Component.onCompleted: { - componentCache = {}; - } - - //TODO: remove? - function get(id) { - return mainLayout.children[id]; - } - - function append(item) { - //FIXME: seems that for one loop the x of the item would continue to be 0 - item.x = item.level * roundedDefaultColumnWidth; - item.parent = mainLayout; - } - - function clear () { - while (mainLayout.children.length > 0) { - remove(0); - } - } - - function remove(id) { - if (id < 0 || id >= count) { - print("Tried to remove an invalid page index:" + id); - return; - } - - var item = mainLayout.children[id]; - if (item.owner) { - item.page.parent = item.owner; + ListView { + id: mainView + z: 99 + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + orientation: Qt.Horizontal + snapMode: ListView.SnapToItem + interactive: root.interactive + currentIndex: root.currentIndex + rightMargin: count > 1 ? pagesLogic.get(count-1).page.width - pagesLogic.get(count-1).width : 0 + preferredHighlightBegin: 0 + preferredHighlightEnd: 0 + highlightMoveDuration: Units.longDuration + onMovementEnded: currentIndex = indexAt(contentX, 0) + onFlickEnded: onMovementEnded(); + model: ObjectModel { + id: pagesLogic + property var componentCache + + property int roundedDefaultColumnWidth: root.width < root.defaultColumnWidth*2 ? root.width : root.defaultColumnWidth + + //NOTE:seems to only work if the array is defined in a declarative way, + //the Object in an imperative way, espacially on Android + Component.onCompleted: { + componentCache = {}; } - //FIXME: why reparent ing is necessary? - //is destroy just an async deleteLater() that isn't executed immediately or it actually leaks? - item.parent = root; - item.destroy(); - } - - function initPage(page, properties) { - var container = containerComponent.createObject(mainLayout, { - "level": pagesLogic.count, - "page": page - }); - - var pageComp; - if (page.createObject) { - // page defined as component - pageComp = page; - } else if (typeof page == "string") { - // page defined as string (a url) - pageComp = pagesLogic.componentCache[page]; - if (!pageComp) { - pageComp = pagesLogic.componentCache[page] = Qt.createComponent(page); + function initPage(page, properties) { + var container = containerComponent.createObject(mainView, { + "level": pagesLogic.count, + "page": page + }); + + var pageComp; + if (page.createObject) { + // page defined as component + pageComp = page; + } else if (typeof page == "string") { + // page defined as string (a url) + pageComp = pagesLogic.componentCache[page]; + if (!pageComp) { + pageComp = pagesLogic.componentCache[page] = Qt.createComponent(page); + } } - } - if (pageComp) { - if (pageComp.status == Component.Error) { - throw new Error("Error while loading page: " + pageComp.errorString()); + if (pageComp) { + if (pageComp.status == Component.Error) { + throw new Error("Error while loading page: " + pageComp.errorString()); + } else { + // instantiate page from component + page = pageComp.createObject(container.pageParent, properties || {}); + } } else { - // instantiate page from component - page = pageComp.createObject(container.pageParent, properties || {}); - } - } else { - // copy properties to the page - for (var prop in properties) { - if (properties.hasOwnProperty(prop)) { - page[prop] = properties[prop]; + // copy properties to the page + for (var prop in properties) { + if (properties.hasOwnProperty(prop)) { + page[prop] = properties[prop]; + } } } - } - - container.page = page; - if (page.parent == null || page.parent == container.pageParent) { - container.owner = null; - } else { - container.owner = page.parent; - } - - // the page has to be reparented - if (page.parent != container) { - page.parent = container; - } - - return container; - } - } - NumberAnimation { - id: scrollAnim - target: mainFlickable - property: "contentX" - duration: Units.longDuration - easing.type: Easing.InOutQuad - } - - Flickable { - id: mainFlickable - anchors.fill: parent - boundsBehavior: Flickable.StopAtBounds - contentWidth: mainLayout.childrenRect.width - contentHeight: height - readonly property Item currentItem: { - var idx = Math.min(currentIndex, pagesLogic.count-1) - return idx>=0 ? pagesLogic.get(idx).page : null - } - //clip only when the app has a sidebar - clip: root.x > 0 - - property int currentIndex: 0 - property int firstVisibleLevel: Math.round (contentX / pagesLogic.roundedDefaultColumnWidth) - - flickDeceleration: Units.gridUnit * 50 - onCurrentItemChanged: { - var itemX = pagesLogic.roundedDefaultColumnWidth * currentIndex; - - if (itemX >= contentX && mainFlickable.currentItem && itemX + mainFlickable.currentItem.width <= contentX + mainFlickable.width) { - return; - } - - //this catches 0 and NaN (sometimes at startup width can oddly be nan - if (!mainFlickable.width) { - return; - } - scrollAnim.running = false; - scrollAnim.from = contentX; - if (itemX < contentX || !mainFlickable.currentItem) { - scrollAnim.to = Math.max(0, Math.min(itemX, mainFlickable.contentWidth - mainFlickable.width)); - } else { - scrollAnim.to = Math.max(0, Math.min(itemX - mainFlickable.width + mainFlickable.currentItem.width, mainFlickable.contentWidth - mainFlickable.width)); - } - scrollAnim.running = true; - } - onMovementEnded: { - if (mainLayout.childrenRect.width == 0) { - return; - } - - scrollAnim.running = false; - scrollAnim.from = contentX; - scrollAnim.to = pagesLogic.roundedDefaultColumnWidth * firstVisibleLevel - scrollAnim.running = true; - - var mappedCurrentItemPos = currentItem.mapToItem(mainFlickable, 0, 0); - - //is the current item out of view? - if (mappedCurrentItemPos.x < 0) { - currentIndex = firstVisibleLevel; - } else if (mappedCurrentItemPos.x + currentItem.width > mainFlickable.width) { - currentIndex = Math.min(root.depth-1, firstVisibleLevel + Math.floor(mainFlickable.width/pagesLogic.roundedDefaultColumnWidth)-1); - } - } - onFlickEnded: movementEnded(); - - Row { - id: mainLayout - add: Transition { - NumberAnimation { - property: "y" - from: mainFlickable.height - to: 0 - duration: Units.shortDuration - easing.type: Easing.InOutQuad - } - } - onChildrenChanged: { - mainFlickable.currentIndex = Math.min(mainFlickable.currentIndex, children.length-1); - } - onWidthChanged: { - //current item in view - if (children[mainFlickable.currentIndex].x >= mainFlickable.contentX && - children[mainFlickable.currentIndex].x + children[mainFlickable.currentIndex].width <= mainFlickable.contentX + mainFlickable.width) { - mainFlickable.contentX = pagesLogic.roundedDefaultColumnWidth * mainFlickable.firstVisibleLevel; + container.page = page; + if (page.parent == null || page.parent == container.pageParent) { + container.owner = null; } else { - mainFlickable.contentX = Math.max(0, Math.min(width - mainFlickable.width, mainFlickable.currentIndex * pagesLogic.roundedDefaultColumnWidth)); + container.owner = page.parent; + } + + // the page has to be reparented + if (page.parent != container) { + page.parent = container; } - + + return container; } - //onChildrenChanged: mainFlickable.contentX = pagesLogic.roundedDefaultColumnWidth * mainFlickable.firstVisibleLevel } - T.ScrollIndicator.horizontal: T.ScrollIndicator { anchors { left: parent.left @@ -425,9 +312,9 @@ MouseArea { id: container - height: mainFlickable.height + height: mainView.height width: root.width - state: root.width < root.defaultColumnWidth*2 ? "vertical" : (container.level >= pagesLogic.count - 1 ? "last" : "middle"); + state: page ? (root.width < root.defaultColumnWidth*2 || pagesLogic.count < 2 ? "vertical" : (container.level >= pagesLogic.count - 1 ? "last" : "middle")) : ""; property int level @@ -467,14 +354,21 @@ target: container width: root.width } + PropertyChanges { + target: container.page.anchors + rightMargin: 0 + } }, State { name: "last" PropertyChanges { target: container - width: { - var page = pagesLogic.get(container.level-1); - Math.max(roundedHint, root.width - (page == undefined ? 0 : page.width)) + width: pagesLogic.roundedDefaultColumnWidth + } + PropertyChanges { + target: container.page.anchors + rightMargin: { + return -(root.width - pagesLogic.roundedDefaultColumnWidth*2); } } }, @@ -484,6 +378,10 @@ target: container width: pagesLogic.roundedDefaultColumnWidth } + PropertyChanges { + target: container.page.anchors + rightMargin: 0 + } } ] }