21 import QtQuick.Layouts 1.2
22 import org.kde.kirigami 1.0
31 readonly
property alias depth: pagesLogic.count
36 readonly
property Item lastItem: pagesLogic.count ? pagesLogic.get(pagesLogic.count - 1).page : null
41 readonly
property Item currentItem: mainFlickable.currentItem
46 property alias currentIndex: mainFlickable.currentIndex
51 property variant initialPage
56 property alias contentItem: mainFlickable
73 property alias interactive: mainFlickable.interactive
99 function push(page, properties) {
104 if (page instanceof Array) {
107 if (page.createObject === undefined && page.parent === undefined && typeof page !=
"string") {
108 properties = properties || page.properties;
116 for (i = 0; i < pages.length; i++) {
117 var tPage = pages[i];
119 if (tPage.createObject === undefined && tPage.parent === undefined && typeof tPage !=
"string") {
120 tProps = tPage.properties;
124 var container = pagesLogic.initPage(tPage, tProps);
125 pagesLogic.append(container);
130 var container = pagesLogic.initPage(page, properties);
131 pagesLogic.append(container);
132 container.visible = container.page.visible =
true;
134 mainFlickable.currentIndex = container.level;
135 return container.page
150 var oldPage = pagesLogic.get(pagesLogic.count-1).page;
151 if (page !== undefined) {
153 while (page != oldPage && pagesLogic.count > 1) {
154 pagesLogic.remove(oldPage.parent.level);
156 oldPage = pagesLogic.get(pagesLogic.count-1).page;
159 pagesLogic.remove(pagesLogic.count-1);
178 function replace(page, properties) {
180 pop(pagesLogic.get(currentIndex-1).page);
181 else if (currentIndex==0)
184 console.warn(
"There's no page to replace");
185 return push(page, properties);
193 return pagesLogic.clear();
197 return pagesLogic.get(idx).page;
205 readonly
property int count: mainLayout.children.length
206 property var componentCache
208 property int roundedDefaultColumnWidth: root.width < root.defaultColumnWidth*2 ? root.width : root.defaultColumnWidth
212 Component.onCompleted: {
218 return mainLayout.children[id];
221 function append(item) {
223 item.x = item.level * roundedDefaultColumnWidth;
224 item.parent = mainLayout;
228 while (mainLayout.children.length > 0) {
233 function remove(id) {
234 if (id < 0 || id >= count) {
235 print(
"Tried to remove an invalid page index:" +
id);
239 var item = mainLayout.children[id];
241 item.page.parent = item.owner;
249 function initPage(page, properties) {
250 var container = containerComponent.createObject(mainLayout, {
251 "level": pagesLogic.count,
256 if (page.createObject) {
259 }
else if (typeof page ==
"string") {
261 pageComp = pagesLogic.componentCache[page];
263 pageComp = pagesLogic.componentCache[page] = Qt.createComponent(page);
267 if (pageComp.status == Component.Error) {
268 throw new Error(
"Error while loading page: " + pageComp.errorString());
271 page = pageComp.createObject(container.pageParent, properties || {});
275 for (var prop in properties) {
276 if (properties.hasOwnProperty(prop)) {
277 page[prop] = properties[prop];
282 container.page = page;
283 if (page.parent == null || page.parent == container.pageParent) {
284 container.owner = null;
286 container.owner = page.parent;
290 if (page.parent != container) {
291 page.parent = container;
300 target: mainFlickable
303 easing.type: Easing.InOutQuad
309 boundsBehavior: Flickable.StopAtBounds
310 contentWidth: mainLayout.childrenRect.width
311 contentHeight: height
312 readonly
property Item currentItem: {
313 var idx = Math.min(currentIndex, pagesLogic.count-1)
314 return idx>=0 ? pagesLogic.get(idx).page : null
319 property int currentIndex: 0
320 property int firstVisibleLevel: Math.round (contentX / pagesLogic.roundedDefaultColumnWidth)
323 onCurrentItemChanged: {
324 var itemX = pagesLogic.roundedDefaultColumnWidth * currentIndex;
326 if (itemX >= contentX && mainFlickable.currentItem && itemX + mainFlickable.currentItem.width <= contentX + mainFlickable.width) {
331 if (!mainFlickable.width) {
334 scrollAnim.running =
false;
335 scrollAnim.from = contentX;
336 if (itemX < contentX || !mainFlickable.currentItem) {
337 scrollAnim.to = Math.max(0, Math.min(itemX, mainFlickable.contentWidth - mainFlickable.width));
339 scrollAnim.to = Math.max(0, Math.min(itemX - mainFlickable.width + mainFlickable.currentItem.width, mainFlickable.contentWidth - mainFlickable.width));
341 scrollAnim.running =
true;
344 if (mainLayout.childrenRect.width == 0) {
348 scrollAnim.running =
false;
349 scrollAnim.from = contentX;
350 scrollAnim.to = pagesLogic.roundedDefaultColumnWidth * firstVisibleLevel
351 scrollAnim.running =
true;
353 var mappedCurrentItemPos = currentItem.mapToItem(mainFlickable, 0, 0);
356 if (mappedCurrentItemPos.x < 0) {
357 currentIndex = firstVisibleLevel;
358 }
else if (mappedCurrentItemPos.x + currentItem.width > mainFlickable.width) {
359 currentIndex = Math.min(root.depth-1, firstVisibleLevel + Math.floor(mainFlickable.width/pagesLogic.roundedDefaultColumnWidth)-1);
362 onFlickEnded: movementEnded();
369 from: mainFlickable.height
372 easing.type: Easing.InOutQuad
377 if (children[mainFlickable.currentIndex].x >= mainFlickable.contentX &&
378 children[mainFlickable.currentIndex].x + children[mainFlickable.currentIndex].width <= mainFlickable.contentX + mainFlickable.width) {
379 mainFlickable.contentX = pagesLogic.roundedDefaultColumnWidth * mainFlickable.firstVisibleLevel;
381 mainFlickable.contentX = Math.max(0, Math.min(width - mainFlickable.width, mainFlickable.currentIndex * pagesLogic.roundedDefaultColumnWidth));
391 width: root.width * root.width/mainLayout.width
392 anchors.bottom: parent.bottom
393 color:
Theme.textColor
395 x: root.width * mainFlickable.visibleArea.xPosition
398 scrollIndicatorTimer.restart();
400 Behavior on opacity {
403 easing.type: Easing.InOutQuad
407 id: scrollIndicatorTimer
409 onTriggered: parent.opacity = 0;
414 id: containerComponent
418 height: mainFlickable.height
421 property string pendingState: root.width < root.defaultColumnWidth*2 ?
"vertical" : (container.level >= pagesLogic.count - 1 ?
"last" :
"middle");
424 onPendingStateChanged: {
425 stateTimer.restart();
430 onTriggered: container.state = container.pendingState
435 property int hint: page && page.implicitWidth ? page.implicitWidth : root.defaultColumnWidth
436 property int roundedHint: Math.floor(root.width/hint) > 0 ? root.width/Math.floor(root.width/hint) : root.width
441 page.parent = container;
442 page.anchors.fill = container;
444 drag.filterChildren:
true
445 onClicked: root.currentIndex = level;
448 root.currentIndex = level;
456 bottom: parent.bottom
460 color:
Theme.textColor
462 visible: container.level < root.depth-1
477 var page = pagesLogic.get(container.level-1);
478 Math.max(roundedHint, root.width - (page == undefined ? 0 : page.width))
486 width: pagesLogic.roundedDefaultColumnWidth
494 SequentialAnimation {
498 easing.type: Easing.InOutQuad
501 script: mainFlickable.currentItemChanged();
509 Component.onCompleted: {
511 push(initialPage, null)
int smallSpacing
units.smallSpacing is the amount of spacing that should be used around smaller UI elements...
int longDuration
units.longDuration should be used for longer, screen-covering animations, for opening and closing of ...
int shortDuration
units.shortDuration should be used for short animations, such as accentuating a UI event...
int gridUnit
The fundamental unit of space that should be used for sizes, expressed in pixels. ...