Warning, /graphics/krita/libs/libqml/plugins/components/PageStack.qml is written in an unsupported language. File is not indexed.
0001 /**************************************************************************** 0002 ** 0003 ** SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org> 0004 ** 0005 ** SPDX-FileCopyrightText: 2011 Nokia Corporation and /or its subsidiary(-ies). 0006 ** All rights reserved. 0007 ** Contact: Nokia Corporation (qt-info@nokia.com) 0008 ** 0009 ** This file is part of the Qt Components project. 0010 ** 0011 ** $QT_BEGIN_LICENSE:BSD$ 0012 ** SPDX-License-Identifier: BSD-3-Clause 0013 ** 0014 ****************************************************************************/ 0015 0016 // The PageStack item defines a container for pages and a stack-based 0017 // navigation model. Pages can be defined as QML items or components. 0018 0019 /**Documented API 0020 Inherits: 0021 Item 0022 0023 Imports: 0024 QtQuick 1.1 0025 . 0026 PageStack.js 0027 0028 Description: 0029 The PageStack component provides a stack-based navigation model that you can use in your application. A stack-based navigation model means that a page of content for your application is pushed onto a stack when the user navigates deeper into the application page hierarchy. The user can then go back to the previous page (or several pages back) by popping a page (or several pages) off the top of the stack. 0030 0031 Properties: 0032 * int depth: 0033 The number of pages on the page stack. 0034 0035 * Item currentPage: 0036 The page in the stack that is currently visible. 0037 0038 * ToolBar toolBar: 0039 The toolbar container for the tools associated with each page. If a toolbar is specified, the tools set for the current page is shown to the user. 0040 If toolbar is null, then no tools are shown even if a page does have tools. 0041 0042 * variant initialPage: 0043 The page to be automatically loaded when this PageStack component gets instantiated. 0044 0045 * bool busy: 0046 Indicates whether there is an ongoing page transition. 0047 0048 Methods: 0049 * clear(): 0050 Clears the page stack of all pages. 0051 0052 * find(function): 0053 This iterates, top to bottom, through all the pages in the page stack and passes each page to the given function. If the specified function returns true, the iterating stops and this function returns the page that produced the true result. If no matching page is found in the page stack, null is returned. 0054 0055 * pop(page, immediate): 0056 When you use pop() with no arguments, it pops the top page off the stack and returns that page to the caller. The normal pop transition animation is performed. If the page popped off the stack is based on the Item element, the page is re-parented back to its original parent. 0057 If the page didn't have an original parent (ie, was created with push(Qt.createComponent("foo.qml")) the page instance will be deleted. 0058 If you give a page argument, the stack is unwound to the given page. Any Item-based pages popped off the stack are re-parented to their original parent. 0059 If the given page is not found in the stack, the stack is unwound to the first page in the stack. However, if you specifically want to unwind the page stack to the first page in the stack, it is best to be explicit about what you are doing and use pop(null) rather than guessing a page that is not on the stack. 0060 The immediate argument defaults to false which means the normal transition animation is performed when a page is popped. If you do not want the transition animation to be performed pass a value of true for immediate. 0061 Note: A pop() on a stack with that contains 0 or 1 pages is a no-operation. 0062 Returns: The page that was top-most on the stack before the pop operation. 0063 0064 * push(page, properties, immediate): 0065 Pushes the given page onto the page stack. You can use a component, item or string for the page. If the page is based on the Item element, the page is re-parented. If a string is used then it is interpreted as a URL that is used to load a page component. The push operation results in the appropriate transition animation being run. If you are pushing an array of pages, the transition animation is only shown for the last page. 0066 Returns: The new top page on the stack. 0067 The page argument can also be an array of pages. In this case, all the pages in the array are pushed onto the stack. The items in the array can be components, items or strings just like for pushing a single page. 0068 The page argument can also be an object that specifies a page with properties or even an array of pages with properties. 0069 The properties argument is optional and allows you to specify values for properties in the page being pushed. 0070 The immediate argument defaults to false which means the normal transition animation is performed when a page is pushed. If you do not want the transition animation to be performed pass a value of true for immediate. 0071 Note: When the stack is empty, a push() or replace() does not perform a transition animation because there is no page to transition from. The only time this normally happens is when an application is starting up so it is not appropriate to have a transition animation anyway. 0072 See also Page. 0073 0074 * replace(page, properties, immediate): 0075 Replaces the top-most page on the stack with page. As in the push() operation, you can use a component, item or string for the page, or even an array of pages. If the page is based on the Item element, the page is re- parented. As in the pop() operation, the replaced page on the stack is re- parented back to its original parent. 0076 Returns: The new top page on the stack. 0077 See also push(). 0078 0079 **/ 0080 0081 import QtQuick 2.3 0082 import org.krita.sketch 1.0 0083 import "." 0084 import "PageStack.js" as Engine 0085 0086 Item { 0087 id: root 0088 0089 width: parent ? parent.width : 0 0090 height: parent ? parent.height : 0 0091 0092 property int depth: Engine.getDepth() 0093 property Item currentPage: null 0094 property Item toolBar 0095 property variant initialPage 0096 0097 property int transitionDuration: Constants.AnimationDuration 0098 0099 // Indicates whether there is an ongoing page transition. 0100 property bool busy: internal.ongoingTransitionCount > 0 0101 0102 // Pushes a page on the stack. 0103 // The page can be defined as a component, item or string. 0104 // If an item is used then the page will get re-parented. 0105 // If a string is used then it is interpreted as a url that is used to load a page component. 0106 // 0107 // The page can also be given as an array of pages. In this case all those pages will be pushed 0108 // onto the stack. The items in the stack can be components, items or strings just like for single 0109 // pages. Additionally an object can be used, which specifies a page and an optional properties 0110 // property. This can be used to push multiple pages while still giving each of them properties. 0111 // When an array is used the transition animation will only be to the last page. 0112 // 0113 // The properties argument is optional and allows defining a map of properties to set on the page. 0114 // If the immediate argument is true then no transition animation is performed. 0115 // Returns the page instance. 0116 function push(page, properties, immediate) 0117 { 0118 return Engine.push(page, properties, false, immediate); 0119 } 0120 0121 // Pops a page off the stack. 0122 // If page is specified then the stack is unwound to that page, to unwind to the first page specify 0123 // page as null. If the immediate argument is true then no transition animation is performed. 0124 // Returns the page instance that was popped off the stack. 0125 function pop(page, immediate) 0126 { 0127 return Engine.pop(page, immediate); 0128 } 0129 0130 // Replaces a page on the stack. 0131 // See push() for details. 0132 function replace(page, properties, immediate) 0133 { 0134 return Engine.push(page, properties, true, immediate); 0135 } 0136 0137 // Clears the page stack. 0138 function clear() 0139 { 0140 return Engine.clear(); 0141 } 0142 0143 // Iterates through all pages (top to bottom) and invokes the specified function. 0144 // If the specified function returns true the search stops and the find function 0145 // returns the page that the iteration stopped at. If the search doesn't result 0146 // in any page being found then null is returned. 0147 function find(func) 0148 { 0149 return Engine.find(func); 0150 } 0151 0152 // Called when the page stack visibility changes. 0153 onVisibleChanged: { 0154 if (currentPage) { 0155 internal.setPageStatus(currentPage, visible ? pageStatus.active : pageStatus.inactive); 0156 if (visible) 0157 currentPage.visible = currentPage.parent.visible = true; 0158 } 0159 } 0160 0161 onInitialPageChanged: { 0162 if (!internal.completed) { 0163 return 0164 } 0165 0166 if (initialPage) { 0167 if (depth == 0) { 0168 push(initialPage, null, true) 0169 } else if (depth == 1) { 0170 replace(initialPage, null, true) 0171 } else { 0172 console.log("Cannot update PageStack.initialPage") 0173 } 0174 } 0175 } 0176 0177 Component.onCompleted: { 0178 internal.completed = true 0179 if (initialPage && depth == 0) 0180 push(initialPage, null, true) 0181 } 0182 0183 QtObject { 0184 id: internal 0185 0186 // The number of ongoing transitions. 0187 property int ongoingTransitionCount: 0 0188 0189 //FIXME: there should be a way to access to them without storing it in an ugly way 0190 property bool completed: false 0191 0192 // Sets the page status. 0193 function setPageStatus(page, status) 0194 { 0195 if (page != null) { 0196 if (page.status !== undefined) { 0197 if (status == pageStatus.active && page.status == pageStatus.inactive) 0198 page.status = pageStatus.activating; 0199 else if (status == pageStatus.inactive && page.status == pageStatus.active) 0200 page.status = pageStatus.deactivating; 0201 0202 page.status = status; 0203 } 0204 } 0205 } 0206 } 0207 0208 QtObject { 0209 id: pageStatus; 0210 0211 property int active: 0; 0212 property int inactive: 1; 0213 property int activating: 2; 0214 property int deactivating: 3; 0215 } 0216 0217 // Component for page containers. 0218 Component { 0219 id: containerComponent 0220 0221 Item { 0222 id: container 0223 0224 width: parent ? parent.width : 0 0225 height: parent ? parent.height : 0 0226 0227 // The states correspond to the different possible positions of the container. 0228 state: "Hidden" 0229 0230 // The page held by this container. 0231 property Item page: null 0232 0233 // The owner of the page. 0234 property Item owner: null 0235 0236 // The width of the longer stack dimension 0237 property int stackWidth: Math.max(root.width, root.height) 0238 0239 // Duration of transition animation (in ms) 0240 0241 0242 // Flag that indicates the container should be cleaned up after the transition has ended. 0243 property bool cleanupAfterTransition: false 0244 0245 // Flag that indicates if page transition animation is running 0246 property bool transitionAnimationRunning: false 0247 0248 // State to be set after previous state change animation has finished 0249 property string pendingState: "none" 0250 0251 // Ensures that transition finish actions are executed 0252 // in case the object is destroyed before reaching the 0253 // end state of an ongoing transition 0254 Component.onDestruction: { 0255 if (transitionAnimationRunning) 0256 transitionEnded(); 0257 } 0258 0259 // Sets pending state as current if state change is delayed 0260 onTransitionAnimationRunningChanged: { 0261 if (!transitionAnimationRunning && pendingState != "none") { 0262 state = pendingState; 0263 pendingState = "none"; 0264 } 0265 } 0266 0267 // Handles state change depending on transition animation status 0268 function setState(newState) 0269 { 0270 if (transitionAnimationRunning) 0271 pendingState = newState; 0272 else 0273 state = newState; 0274 } 0275 0276 // Performs a push enter transition. 0277 function pushEnter(immediate, orientationChanges) 0278 { 0279 if (!immediate) { 0280 if (orientationChanges) 0281 setState("LandscapeRight"); 0282 else 0283 setState("Right"); 0284 } 0285 setState(""); 0286 page.visible = true; 0287 if (root.visible && immediate) 0288 internal.setPageStatus(page, pageStatus.active); 0289 } 0290 0291 // Performs a push exit transition. 0292 function pushExit(replace, immediate, orientationChanges) 0293 { 0294 if (orientationChanges) 0295 setState(immediate ? "Hidden" : "LandscapeLeft"); 0296 else 0297 setState(immediate ? "Hidden" : "Left"); 0298 if (root.visible && immediate) 0299 internal.setPageStatus(page, pageStatus.inactive); 0300 if (replace) { 0301 if (immediate) 0302 cleanup(); 0303 else 0304 cleanupAfterTransition = true; 0305 } 0306 } 0307 0308 // Performs a pop enter transition. 0309 function popEnter(immediate, orientationChanges) 0310 { 0311 if (!immediate) 0312 state = orientationChanges ? "LandscapeLeft" : "Left"; 0313 setState(""); 0314 page.visible = true; 0315 if (root.visible && immediate) 0316 internal.setPageStatus(page, pageStatus.active); 0317 } 0318 0319 // Performs a pop exit transition. 0320 function popExit(immediate, orientationChanges) 0321 { 0322 if (orientationChanges) 0323 setState(immediate ? "Hidden" : "LandscapeRight"); 0324 else 0325 setState(immediate ? "Hidden" : "Right"); 0326 0327 if (root.visible && immediate) 0328 internal.setPageStatus(page, pageStatus.inactive); 0329 if (immediate) 0330 cleanup(); 0331 else 0332 cleanupAfterTransition = true; 0333 } 0334 0335 // Called when a transition has started. 0336 function transitionStarted() 0337 { 0338 transitionAnimationRunning = true; 0339 internal.ongoingTransitionCount++; 0340 if (root.visible) { 0341 internal.setPageStatus(page, (state == "") ? pageStatus.activating : pageStatus.deactivating); 0342 } 0343 } 0344 0345 // Called when a transition has ended. 0346 function transitionEnded() 0347 { 0348 if (state != "") 0349 state = "Hidden"; 0350 if (root.visible) 0351 internal.setPageStatus(page, (state == "") ? pageStatus.active : pageStatus.inactive); 0352 0353 internal.ongoingTransitionCount--; 0354 transitionAnimationRunning = false; 0355 if (cleanupAfterTransition) 0356 cleanup(); 0357 } 0358 0359 states: [ 0360 // Explicit properties for default state. 0361 State { 0362 name: "" 0363 PropertyChanges { target: container; visible: true; opacity: 1 } 0364 }, 0365 // Start state for pop entry, end state for push exit. 0366 State { 0367 name: "Left" 0368 PropertyChanges { target: container; x: -width / 2; opacity: 0 } 0369 }, 0370 // Start state for pop entry, end state for push exit 0371 // when exiting portrait and entering landscape. 0372 State { 0373 name: "LandscapeLeft" 0374 PropertyChanges { target: container; x: -stackWidth / 2; opacity: 0 } 0375 }, 0376 // Start state for push entry, end state for pop exit. 0377 State { 0378 name: "Right" 0379 PropertyChanges { target: container; x: width / 2; opacity: 0 } 0380 }, 0381 // Start state for push entry, end state for pop exit 0382 // when exiting portrait and entering landscape. 0383 State { 0384 name: "LandscapeRight" 0385 PropertyChanges { target: container; x: stackWidth / 2; opacity: 0 } 0386 }, 0387 // Inactive state. 0388 State { 0389 name: "Hidden" 0390 PropertyChanges { target: container; visible: false } 0391 } 0392 ] 0393 0394 transitions: [ 0395 // Push exit transition 0396 Transition { 0397 from: ""; to: "Left" 0398 SequentialAnimation { 0399 ScriptAction { script: transitionStarted() } 0400 ParallelAnimation { 0401 PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration } 0402 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0403 } 0404 ScriptAction { script: transitionEnded() } 0405 } 0406 }, 0407 // Pop entry transition 0408 Transition { 0409 from: "Left"; to: "" 0410 SequentialAnimation { 0411 ScriptAction { script: transitionStarted() } 0412 ParallelAnimation { 0413 PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration } 0414 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0415 } 0416 ScriptAction { script: transitionEnded() } 0417 } 0418 }, 0419 // Push exit transition landscape 0420 Transition { 0421 from: ""; to: "LandscapeLeft" 0422 SequentialAnimation { 0423 ScriptAction { script: transitionStarted() } 0424 ParallelAnimation { 0425 PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration } 0426 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0427 } 0428 ScriptAction { script: transitionEnded() } 0429 } 0430 }, 0431 // Pop entry transition landscape 0432 Transition { 0433 from: "LandscapeLeft"; to: "" 0434 SequentialAnimation { 0435 ScriptAction { script: transitionStarted() } 0436 ParallelAnimation { 0437 PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration } 0438 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0439 } 0440 ScriptAction { script: transitionEnded() } 0441 } 0442 }, 0443 // Pop exit transition 0444 Transition { 0445 from: ""; to: "Right" 0446 SequentialAnimation { 0447 ScriptAction { script: transitionStarted() } 0448 ParallelAnimation { 0449 PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration } 0450 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0451 } 0452 // Workaround for transition animation bug causing ghost view with page pop transition animation 0453 // TODO: Root cause still unknown 0454 PropertyAnimation {} 0455 ScriptAction { script: transitionEnded() } 0456 } 0457 }, 0458 // Push entry transition 0459 Transition { 0460 from: "Right"; to: "" 0461 SequentialAnimation { 0462 ScriptAction { script: transitionStarted() } 0463 ParallelAnimation { 0464 PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration } 0465 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0466 } 0467 ScriptAction { script: transitionEnded() } 0468 } 0469 }, 0470 // Pop exit transition landscape 0471 Transition { 0472 from: ""; to: "LandscapeRight" 0473 SequentialAnimation { 0474 ScriptAction { script: transitionStarted() } 0475 ParallelAnimation { 0476 PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration } 0477 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0478 } 0479 // Workaround for transition animation bug causing ghost view with page pop transition animation 0480 // TODO: Root cause still unknown 0481 PropertyAnimation {} 0482 ScriptAction { script: transitionEnded() } 0483 } 0484 }, 0485 // Push entry transition landscape 0486 Transition { 0487 from: "LandscapeRight"; to: "" 0488 SequentialAnimation { 0489 ScriptAction { script: transitionStarted() } 0490 ParallelAnimation { 0491 PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration } 0492 PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration } 0493 } 0494 ScriptAction { script: transitionEnded() } 0495 } 0496 } 0497 ] 0498 0499 // Cleans up the container and then destroys it. 0500 function cleanup() 0501 { 0502 if (page != null) { 0503 if (page.status == pageStatus.active) { 0504 internal.setPageStatus(page, pageStatus.inactive) 0505 } 0506 if (owner != container) { 0507 // container is not the owner of the page - re-parent back to original owner 0508 page.visible = false; 0509 page.anchors.fill = undefined 0510 page.parent = owner; 0511 } 0512 } 0513 0514 container.destroy(); 0515 } 0516 } 0517 } 0518 } 0519