• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kde-runtime API Reference
  • KDE Home
  • Contact Us
 

PlasmaExtraComponents

  • sources
  • kde-4.14
  • kde-runtime
  • plasma
  • declarativeimports
  • plasmaextracomponents
  • qml
PageRow.qml
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Marco Martin <mart@kde.org>
4 **
5 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 ** All rights reserved.
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** This file is part of the Qt Components project.
10 **
11 ** $QT_BEGIN_LICENSE:BSD$
12 ** You may use this file under the terms of the BSD license as follows:
13 **
14 ** "Redistribution and use in source and binary forms, with or without
15 ** modification, are permitted provided that the following conditions are
16 ** met:
17 ** * Redistributions of source code must retain the above copyright
18 ** notice, this list of conditions and the following disclaimer.
19 ** * Redistributions in binary form must reproduce the above copyright
20 ** notice, this list of conditions and the following disclaimer in
21 ** the documentation and/or other materials provided with the
22 ** distribution.
23 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
24 ** the names of its contributors may be used to endorse or promote
25 ** products derived from this software without specific prior written
26 ** permission.
27 **
28 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42 
43 import QtQuick 1.1
44 import org.kde.plasma.components 0.1
45 import org.kde.plasma.core 0.1 as PlasmaCore
46 
47 import "../components/private/PageStack.js" as Engine
48 
49 Item {
50  id: actualRoot
51 
52  width: parent ? parent.width : 0
53  height: parent ? parent.height : 0
54 
55 
56  property int depth: Engine.getDepth()
57  property Item currentPage: null
58  property ToolBar toolBar
59  property variant initialPage
60  //A column is wide enough for 30 characters
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
62 
63  property alias clip: scrollArea.clip
64 
65  // Indicates whether there is an ongoing page transition.
66  property bool busy: internal.ongoingTransitionCount > 0
67 
68  // Pushes a page on the stack.
69  // The page can be defined as a component, item or string.
70  // If an item is used then the page will get re-parented.
71  // If a string is used then it is interpreted as a url that is used to load a page component.
72  //
73  // The page can also be given as an array of pages. In this case all those pages will be pushed
74  // onto the stack. The items in the stack can be components, items or strings just like for single
75  // pages. Additionally an object can be used, which specifies a page and an optional properties
76  // property. This can be used to push multiple pages while still giving each of them properties.
77  // When an array is used the transition animation will only be to the last page.
78  //
79  // The properties argument is optional and allows defining a map of properties to set on the page.
80  // If the immediate argument is true then no transition animation is performed.
81  // Returns the page instance.
82  function push(page, properties, immediate)
83  {
84  var item = Engine.push(page, properties, false, immediate)
85  scrollToLevel(depth)
86  return item
87  }
88 
89  // Pops a page off the stack.
90  // If page is specified then the stack is unwound to that page, to unwind to the first page specify
91  // page as null. If the immediate argument is true then no transition animation is performed.
92  // Returns the page instance that was popped off the stack.
93  function pop(page, immediate)
94  {
95  return Engine.pop(page, immediate);
96  }
97 
98  // Replaces a page on the stack.
99  // See push() for details.
100  function replace(page, properties, immediate)
101  {
102  var item = Engine.push(page, properties, true, immediate);
103  scrollToLevel(depth)
104  return item
105  }
106 
107  // Clears the page stack.
108  function clear()
109  {
110  return Engine.clear();
111  }
112 
113  // Iterates through all pages (top to bottom) and invokes the specified function.
114  // If the specified function returns true the search stops and the find function
115  // returns the page that the iteration stopped at. If the search doesn't result
116  // in any page being found then null is returned.
117  function find(func)
118  {
119  return Engine.find(func);
120  }
121 
122  // Scroll the view to have the page of the given level as first item
123  function scrollToLevel(level)
124  {
125  if (level < 0 || level > depth || root.width < width) {
126  return
127  }
128 
129  scrollAnimation.to = Math.max(0, Math.min(Math.max(0, columnWidth * level - columnWidth), mainFlickable.contentWidth - mainFlickable.width))
130  scrollAnimation.running = true
131  }
132 
133  NumberAnimation {
134  id: scrollAnimation
135  target: mainFlickable
136  properties: "contentX"
137  duration: internal.transitionDuration
138  easing.type: Easing.InOutQuad
139  }
140 
141  // Called when the page stack visibility changes.
142  onVisibleChanged: {
143  if (currentPage) {
144  internal.setPageStatus(currentPage, visible ? PageStatus.Active : PageStatus.Inactive);
145  if (visible)
146  currentPage.visible = currentPage.parent.visible = true;
147  }
148  }
149 
150  onInitialPageChanged: {
151  if (!internal.completed) {
152  return
153  }
154 
155  if (initialPage) {
156  if (depth == 0) {
157  push(initialPage, null, true)
158  } else if (depth == 1) {
159  replace(initialPage, null, true)
160  } else {
161  console.log("Cannot update PageStack.initialPage")
162  }
163  }
164  }
165 
166  Component.onCompleted: {
167  internal.completed = true
168  if (initialPage && depth == 0)
169  push(initialPage, null, true)
170  }
171 
172  QtObject {
173  id: internal
174 
175  // The number of ongoing transitions.
176  property int ongoingTransitionCount: 0
177 
178  //FIXME: there should be a way to access to theh without storing it in an ugly way
179  property bool completed: false
180 
181  // Duration of transition animation (in ms)
182  property int transitionDuration: 250
183 
184  // Sets the page status.
185  function setPageStatus(page, status)
186  {
187  if (page != null) {
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;
193 
194  page.status = status;
195  }
196  }
197  }
198  }
199 
200  ScrollArea {
201  id: scrollArea
202  anchors.fill: parent
203  Flickable {
204  id: mainFlickable
205  anchors.fill: parent
206  interactive: root.width > width
207  boundsBehavior: Flickable.StopAtBounds
208  contentWidth: root.width
209  contentHeight: height
210  Row {
211  id: root
212  spacing: -100
213  width: Math.max((depth-1+children[children.length-1].takenColumns) * columnWidth, childrenRect.width - 100)
214 
215  height: parent.height
216  }
217  onMovementEnded: {
218  scrollToLevel(Math.round(contentX/columnWidth)+1)
219  }
220  }
221  }
222 
223  Component {
224  id: svgShadowComponent
225  PlasmaCore.SvgItem {
226  property Item container
227  z: 800
228  svg: PlasmaCore.Svg {imagePath: "widgets/scrollwidget"}
229  elementId: "border-left"
230  width: naturalSize.width
231  opacity: container.pageDepth == actualRoot.depth ? 1 : 0.7
232  anchors {
233  left: container.pageParent.right
234  top: container.pageParent.top
235  bottom: container.pageParent.bottom
236  }
237  Behavior on opacity {
238  NumberAnimation {
239  duration: internal.transitionDuration
240  easing.type: Easing.InOutQuad
241  }
242  }
243  }
244  }
245 
246  // Component for page containers.
247  Component {
248  id: containerComponent
249 
250  Item {
251  id: container
252 
253  implicitWidth: actualContainer.width + 100
254  width: implicitWidth
255  height: parent ? parent.height : 0
256 
257  x: 0
258 
259  // The actual parent of page: page will anchor to that
260  property Item pageParent: actualContainer
261 
262  property int pageDepth: 0
263  Component.onCompleted: {
264  pageDepth = Engine.getDepth() + 1
265  container.z = -Engine.getDepth()
266  }
267 
268  // The states correspond to the different possible positions of the container.
269  state: "Hidden"
270 
271  // The page held by this container.
272  property Item page: null
273 
274  // The owner of the page.
275  property Item owner: null
276 
277  // The width of the longer stack dimension
278  property int stackWidth: Math.max(actualRoot.width, actualRoot.height)
279 
280 
281  // Flag that indicates the container should be cleaned up after the transition has ended.
282  property bool cleanupAfterTransition: false
283 
284  // Flag that indicates if page transition animation is running
285  property bool transitionAnimationRunning: false
286 
287  // State to be set after previous state change animation has finished
288  property string pendingState: "none"
289 
290  //how many columns take the page?
291  property alias takenColumns: actualContainer.takenColumns
292 
293  // Ensures that transition finish actions are executed
294  // in case the object is destroyed before reaching the
295  // end state of an ongoing transition
296  Component.onDestruction: {
297  if (transitionAnimationRunning)
298  transitionEnded();
299  }
300 
301  Item {
302  id: actualContainer
303 
304  anchors {
305  top: parent.top
306  bottom: parent.bottom
307  right: parent.right
308  rightMargin: 100
309  }
310 
311  property int takenColumns: Math.max(1, Math.round(container.page ? container.page.implicitWidth/columnWidth : 1));
312 
313  width: (container.pageDepth >= actualRoot.depth ? Math.min(actualRoot.width, takenColumns*columnWidth) : columnWidth)
314  }
315 
316  Image {
317  z: 800
318  source: "image://appbackgrounds/shadow-right"
319  fillMode: Image.TileVertically
320  opacity: container.pageDepth == actualRoot.depth ? 1 : 0.7
321  anchors {
322  left: actualContainer.right
323  top: actualContainer.top
324  bottom: actualContainer.bottom
325  }
326  Behavior on opacity {
327  NumberAnimation {
328  duration: internal.transitionDuration
329  easing.type: Easing.InOutQuad
330  }
331  }
332  onStatusChanged: {
333  if (status == Image.Error) {
334  var shadow = svgShadowComponent.createObject(container)
335  shadow.container = container
336  destroy()
337  }
338  }
339  }
340 
341  // Sets pending state as current if state change is delayed
342  onTransitionAnimationRunningChanged: {
343  if (!transitionAnimationRunning && pendingState != "none") {
344  state = pendingState;
345  pendingState = "none";
346  }
347  }
348 
349  // Handles state change depening on transition animation status
350  function setState(newState)
351  {
352  if (transitionAnimationRunning)
353  pendingState = newState;
354  else
355  state = newState;
356  }
357 
358  // Performs a push enter transition.
359  function pushEnter(immediate, orientationChanges)
360  {
361  if (!immediate) {
362  setState("Right");
363  }
364  setState("");
365  page.visible = true;
366  if (actualRoot.visible && immediate)
367  internal.setPageStatus(page, PageStatus.Active);
368  }
369 
370  // Performs a push exit transition.
371  function pushExit(replace, immediate, orientationChanges)
372  {
373  if (replace) {
374  setState(immediate ? "Hidden" : "Left");
375  }
376 
377  if (actualRoot.visible && immediate)
378  internal.setPageStatus(page, PageStatus.Inactive);
379  if (replace) {
380  if (immediate)
381  cleanup();
382  else
383  cleanupAfterTransition = true;
384  }
385  }
386 
387  // Performs a pop enter transition.
388  function popEnter(immediate, orientationChanges)
389  {
390  setState("");
391  page.visible = true;
392  if (actualRoot.visible && immediate)
393  internal.setPageStatus(page, PageStatus.Active);
394  }
395 
396  // Performs a pop exit transition.
397  function popExit(immediate, orientationChanges)
398  {
399  setState(immediate ? "Hidden" : "Left");
400 
401  if (actualRoot.visible && immediate)
402  internal.setPageStatus(page, PageStatus.Inactive);
403  if (immediate)
404  cleanup();
405  else
406  cleanupAfterTransition = true;
407  }
408 
409  // Called when a transition has started.
410  function transitionStarted()
411  {
412  container.clip = true
413  transitionAnimationRunning = true;
414  internal.ongoingTransitionCount++;
415  if (actualRoot.visible) {
416  internal.setPageStatus(page, (state == "") ? PageStatus.Activating : PageStatus.Deactivating);
417  }
418  }
419 
420  // Called when a transition has ended.
421  function transitionEnded()
422  {
423  container.clip = false
424  if (state != "")
425  state = "Hidden";
426  if (actualRoot.visible)
427  internal.setPageStatus(page, (state == "") ? PageStatus.Active : PageStatus.Inactive);
428 
429  internal.ongoingTransitionCount--;
430  transitionAnimationRunning = false;
431 
432  if (cleanupAfterTransition) {
433  cleanup();
434  }
435  }
436 
437  states: [
438  // Explicit properties for default state.
439  State {
440  name: ""
441  PropertyChanges { target: container; visible: true; opacity: 1 }
442  PropertyChanges { target: container; width: container.implicitWidth}
443  },
444  // Start state for pop entry, end state for push exit.
445  State {
446  name: "Left"
447  PropertyChanges { target: container; opacity: 0 }
448  PropertyChanges { target: container; width: 100}
449  },
450  // Start state for push entry, end state for pop exit.
451  State {
452  name: "Right"
453  PropertyChanges { target: container; opacity: 0 }
454  PropertyChanges { target: container; width: 100}
455  },
456  // Inactive state.
457  State {
458  name: "Hidden"
459  PropertyChanges { target: container; visible: false }
460  PropertyChanges { target: container; width: container.implicitWidth}
461  }
462  ]
463 
464  transitions: [
465  // Push exit transition
466  Transition {
467  from: ""; to: "Left"
468  SequentialAnimation {
469  ScriptAction { script: transitionStarted() }
470  ParallelAnimation {
471  PropertyAnimation { properties: "width"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
472  PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
473  }
474  ScriptAction { script: transitionEnded() }
475  }
476  },
477  // Pop entry transition
478  Transition {
479  from: "Left"; to: ""
480  SequentialAnimation {
481  ScriptAction { script: transitionStarted() }
482  ParallelAnimation {
483  PropertyAnimation { properties: "width"; easing.type: Easing.OutQuad; duration: internal.transitionDuration }
484  PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
485  }
486  ScriptAction { script: transitionEnded() }
487  }
488  },
489  // Pop exit transition
490  Transition {
491  from: ""; to: "Right"
492  SequentialAnimation {
493  ScriptAction { script: transitionStarted() }
494  ParallelAnimation {
495  PropertyAnimation { properties: "width"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
496  PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
497  }
498  // Workaround for transition animation bug causing ghost view with page pop transition animation
499  // TODO: Root cause still unknown
500  PropertyAnimation {}
501  ScriptAction { script: transitionEnded() }
502  }
503  },
504  // Push entry transition
505  Transition {
506  from: "Right"; to: ""
507  SequentialAnimation {
508  ScriptAction { script: transitionStarted() }
509  ParallelAnimation {
510  PropertyAnimation { properties: "width"; easing.type: Easing.OutQuad; duration: internal.transitionDuration }
511  PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration }
512  }
513  ScriptAction { script: transitionEnded() }
514  }
515  }
516  ]
517 
518  // Cleans up the container and then destroys it.
519  function cleanup()
520  {
521  if (page != null) {
522  if (page.status == PageStatus.Active) {
523  internal.setPageStatus(page, PageStatus.Inactive)
524  }
525  }
526  container.visible = false;
527  container.destroy();
528  }
529  }
530  }
531 }
SequentialAnimation
ScrollArea
This item takes a Flickable and automatically puts scrollbars in adjusting the layout if needed...
Definition: ScrollArea.qml:29
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:08:46 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

PlasmaExtraComponents

Skip menu "PlasmaExtraComponents"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kde-runtime API Reference

Skip menu "kde-runtime API Reference"
  • KCMShell
  • KNotify
  • Plasma Runtime
  •     PlasmaCore
  •     DragAndDrop
  •     PlasmaComponents
  •     PlasmaExtraComponents
  •     QtExtraComponents

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal