44 import org.kde.plasma.components 0.1
45 import org.kde.plasma.core 0.1 as PlasmaCore
47 import "../components/private/PageStack.js" as Engine
52 width: parent ? parent.width : 0
53 height: parent ? parent.height : 0
56 property int depth: Engine.getDepth()
57 property Item currentPage: null
58 property ToolBar toolBar
59 property variant initialPage
61 property int columnWidth: Math.round(parent.width/(theme.defaultFont.mSize.width*30)) > 0 ? parent.width/Math.round(parent.width/(theme.defaultFont.mSize.width*30)) : width
63 property alias clip: scrollArea.clip
66 property bool busy:
internal.ongoingTransitionCount > 0
82 function push(page, properties, immediate)
84 var item = Engine.push(page, properties,
false, immediate)
93 function pop(page, immediate)
95 return Engine.pop(page, immediate);
100 function replace(page, properties, immediate)
102 var item = Engine.push(page, properties,
true, immediate);
110 return Engine.clear();
119 return Engine.find(func);
123 function scrollToLevel(level)
125 if (level < 0 || level > depth || root.width < width) {
129 scrollAnimation.to = Math.max(0, Math.min(Math.max(0, columnWidth * level - columnWidth), mainFlickable.contentWidth - mainFlickable.width))
130 scrollAnimation.running =
true
135 target: mainFlickable
136 properties:
"contentX"
137 duration:
internal.transitionDuration
138 easing.type: Easing.InOutQuad
144 internal.setPageStatus(currentPage, visible ? PageStatus.Active : PageStatus.Inactive);
146 currentPage.visible = currentPage.parent.visible =
true;
150 onInitialPageChanged: {
151 if (!
internal.completed) {
157 push(initialPage, null,
true)
158 }
else if (depth == 1) {
159 replace(initialPage, null,
true)
161 console.log(
"Cannot update PageStack.initialPage")
166 Component.onCompleted: {
167 internal.completed =
true
168 if (initialPage && depth == 0)
169 push(initialPage, null,
true)
176 property int ongoingTransitionCount: 0
179 property bool completed:
false
182 property int transitionDuration: 250
185 function setPageStatus(page, status)
188 if (page.status !== undefined) {
189 if (status == PageStatus.Active && page.status == PageStatus.Inactive)
190 page.status = PageStatus.Activating;
191 else if (status == PageStatus.Inactive && page.status == PageStatus.Active)
192 page.status = PageStatus.Deactivating;
194 page.status = status;
206 interactive: root.width > width
207 boundsBehavior: Flickable.StopAtBounds
208 contentWidth: root.width
209 contentHeight: height
213 width: Math.max((depth-1+children[children.length-1].takenColumns) * columnWidth, childrenRect.width - 100)
215 height: parent.height
218 scrollToLevel(Math.round(contentX/columnWidth)+1)
224 id: svgShadowComponent
226 property Item container
228 svg: PlasmaCore.Svg {imagePath:
"widgets/scrollwidget"}
229 elementId:
"border-left"
230 width: naturalSize.width
231 opacity: container.pageDepth == actualRoot.depth ? 1 : 0.7
233 left: container.pageParent.right
234 top: container.pageParent.top
235 bottom: container.pageParent.bottom
237 Behavior on opacity {
239 duration:
internal.transitionDuration
240 easing.type: Easing.InOutQuad
248 id: containerComponent
253 implicitWidth: actualContainer.width + 100
255 height: parent ? parent.height : 0
260 property Item pageParent: actualContainer
262 property int pageDepth: 0
263 Component.onCompleted: {
264 pageDepth = Engine.getDepth() + 1
265 container.z = -Engine.getDepth()
272 property Item page: null
275 property Item owner: null
278 property int stackWidth: Math.max(actualRoot.width, actualRoot.height)
282 property bool cleanupAfterTransition:
false
285 property bool transitionAnimationRunning:
false
288 property string pendingState:
"none"
291 property alias takenColumns: actualContainer.takenColumns
296 Component.onDestruction: {
297 if (transitionAnimationRunning)
306 bottom: parent.bottom
311 property int takenColumns: Math.max(1, Math.round(container.page ? container.page.implicitWidth/columnWidth : 1));
313 width: (container.pageDepth >= actualRoot.depth ? Math.min(actualRoot.width, takenColumns*columnWidth) : columnWidth)
318 source:
"image://appbackgrounds/shadow-right"
319 fillMode: Image.TileVertically
320 opacity: container.pageDepth == actualRoot.depth ? 1 : 0.7
322 left: actualContainer.right
323 top: actualContainer.top
324 bottom: actualContainer.bottom
326 Behavior on opacity {
328 duration:
internal.transitionDuration
329 easing.type: Easing.InOutQuad
333 if (status == Image.Error) {
334 var shadow = svgShadowComponent.createObject(container)
335 shadow.container = container
342 onTransitionAnimationRunningChanged: {
343 if (!transitionAnimationRunning && pendingState !=
"none") {
344 state = pendingState;
345 pendingState =
"none";
350 function setState(newState)
352 if (transitionAnimationRunning)
353 pendingState = newState;
359 function pushEnter(immediate, orientationChanges)
366 if (actualRoot.visible && immediate)
367 internal.setPageStatus(page, PageStatus.Active);
371 function pushExit(replace, immediate, orientationChanges)
374 setState(immediate ?
"Hidden" :
"Left");
377 if (actualRoot.visible && immediate)
378 internal.setPageStatus(page, PageStatus.Inactive);
383 cleanupAfterTransition =
true;
388 function popEnter(immediate, orientationChanges)
392 if (actualRoot.visible && immediate)
393 internal.setPageStatus(page, PageStatus.Active);
397 function popExit(immediate, orientationChanges)
399 setState(immediate ?
"Hidden" :
"Left");
401 if (actualRoot.visible && immediate)
402 internal.setPageStatus(page, PageStatus.Inactive);
406 cleanupAfterTransition =
true;
410 function transitionStarted()
412 container.clip =
true
413 transitionAnimationRunning =
true;
414 internal.ongoingTransitionCount++;
415 if (actualRoot.visible) {
416 internal.setPageStatus(page, (state ==
"") ? PageStatus.Activating : PageStatus.Deactivating);
421 function transitionEnded()
423 container.clip =
false
426 if (actualRoot.visible)
427 internal.setPageStatus(page, (state ==
"") ? PageStatus.Active : PageStatus.Inactive);
429 internal.ongoingTransitionCount--;
430 transitionAnimationRunning =
false;
432 if (cleanupAfterTransition) {
441 PropertyChanges { target: container; visible:
true; opacity: 1 }
442 PropertyChanges { target: container; width: container.implicitWidth}
447 PropertyChanges { target: container; opacity: 0 }
448 PropertyChanges { target: container; width: 100}
453 PropertyChanges { target: container; opacity: 0 }
454 PropertyChanges { target: container; width: 100}
459 PropertyChanges { target: container; visible:
false }
460 PropertyChanges { target: container; width: container.implicitWidth}
469 ScriptAction { script: transitionStarted() }
471 PropertyAnimation { properties:
"width"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
472 PropertyAnimation { properties:
"opacity"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
474 ScriptAction { script: transitionEnded() }
481 ScriptAction { script: transitionStarted() }
483 PropertyAnimation { properties:
"width"; easing.type: Easing.OutQuad; duration:
internal.transitionDuration }
484 PropertyAnimation { properties:
"opacity"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
486 ScriptAction { script: transitionEnded() }
491 from:
""; to:
"Right"
493 ScriptAction { script: transitionStarted() }
495 PropertyAnimation { properties:
"width"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
496 PropertyAnimation { properties:
"opacity"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
501 ScriptAction { script: transitionEnded() }
506 from:
"Right"; to:
""
508 ScriptAction { script: transitionStarted() }
510 PropertyAnimation { properties:
"width"; easing.type: Easing.OutQuad; duration:
internal.transitionDuration }
511 PropertyAnimation { properties:
"opacity"; easing.type: Easing.InQuad; duration:
internal.transitionDuration }
513 ScriptAction { script: transitionEnded() }
522 if (page.status == PageStatus.Active) {
523 internal.setPageStatus(page, PageStatus.Inactive)
526 container.visible =
false;