Unity 8
 All Classes Functions Properties
LazyImage.qml
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
4  * Authors:
5  * MichaƂ Sawicz <michal.sawicz@canonical.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 import QtQuick 2.0
21 import Ubuntu.Components 0.1
22 
23 Item {
24  id: root
25 
26  property url source
27  // TODO convert into enums when available in QML
28  property string scaleTo
29 
30  property real initialWidth: scaleTo == "width" || scaleTo == "fit" ? width : units.gu(10)
31  property real initialHeight: scaleTo == "height" || scaleTo == "fit" ? height : units.gu(10)
32 
33  property alias sourceSize: image.sourceSize
34  property alias fillMode: image.fillMode
35  property alias asynchronous: image.asynchronous
36  property alias cache: image.cache
37  property alias horizontalAlignment: image.horizontalAlignment
38  property alias verticalAlignment: image.verticalAlignment
39  property alias sourceImage: image
40 
41  state: "default"
42 
43  onSourceChanged: {
44  if (state === "ready") {
45  state = "default";
46  image.nextSource = source;
47  } else {
48  image.source = source;
49  }
50  }
51 
52  UbuntuShape {
53  id: placeholder
54  objectName: "placeholder"
55  color: "#22FFFFFF"
56  anchors.fill: shape
57  visible: opacity != 0
58 
59  ActivityIndicator {
60  id: activity
61  anchors.centerIn: parent
62  opacity: 0
63  visible: opacity != 0
64 
65  running: visible
66  }
67 
68  Image {
69  id: errorImage
70  objectName: "errorImage"
71  anchors.centerIn: parent
72  opacity: 0
73  visible: opacity != 0
74 
75  source: "graphics/close.png"
76  sourceSize { width: units.gu(3); height: units.gu(3) }
77  }
78  }
79 
80  UbuntuShape {
81  id: shape
82  objectName: "shape"
83  height: root.initialHeight
84  width: root.initialWidth
85  anchors.centerIn: root.scaleTo == "fit" ? parent : undefined
86 
87  opacity: 0
88  visible: opacity != 0
89 
90  image: Image {
91  id: image
92  objectName: "image"
93 
94  property url nextSource
95  property string format: image.implicitWidth > image.implicitHeight ? "landscape" : "portrait"
96 
97  fillMode: Image.PreserveAspectFit
98  asynchronous: true
99  cache: false
100  horizontalAlignment: Image.AlignHCenter
101  verticalAlignment: Image.AlignVCenter
102  sourceSize.width: root.scaleTo == "width" ? root.width
103  : root.scaleTo == "fit" && root.width <= root.height ? root.width
104  : 0
105  sourceSize.height: root.scaleTo == "height" ? root.height
106  : root.scaleTo == "fit" && root.height <= root.width ? root.height
107  : 0
108  }
109  }
110 
111  states: [
112  State {
113  name: "default"
114  when: image.source == ""
115  PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
116  PropertyChanges { target: errorImage; opacity: 0 }
117  },
118  State {
119  name: "loading"
120  extend: "default"
121  when: image.status === Image.Loading
122  PropertyChanges { target: activity; opacity: 1 }
123  },
124  State {
125  name: "ready"
126  when: image.status === Image.Ready && image.source != ""
127  PropertyChanges { target: root; implicitWidth: shape.width; implicitHeight: shape.height }
128  PropertyChanges { target: placeholder; opacity: 0 }
129  PropertyChanges { target: shape; opacity: 1
130  width: root.scaleTo == "width" || (root.scaleTo == "fit" && image.format == "landscape") ? root.width
131  : root.scaleTo == "" ? image.implicitWidth : image.implicitWidth * height / image.implicitHeight
132  height: root.scaleTo == "height" || (root.scaleTo == "fit" && image.format == "portrait") ? root.height
133  : root.scaleTo == "" ? image.implicitHeight : image.implicitHeight * width / image.implicitWidth
134  }
135  },
136  State {
137  name: "error"
138  extend: "default"
139  when: image.status === Image.Error
140  PropertyChanges { target: errorImage; opacity: 1.0 }
141  }
142  ]
143 
144  transitions: [
145  Transition {
146  to: "ready"
147  objectName: "readyTransition"
148  SequentialAnimation {
149  PropertyAction { target: shape; property: "visible" }
150  ParallelAnimation {
151  NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
152  UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
153  UbuntuNumberAnimation { target: shape; properties: "width,height" }
154  NumberAnimation {
155  targets: [placeholder, activity, errorImage]; property: "opacity";
156  easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
157  }
158  }
159  }
160  },
161 
162  Transition {
163  to: "*"
164  objectName: "genericTransition"
165  SequentialAnimation {
166  ParallelAnimation {
167  NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
168  NumberAnimation {
169  targets: [placeholder, activity, errorImage]; property: "opacity";
170  easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
171  }
172  UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
173  UbuntuNumberAnimation { target: shape; properties: "width,height" }
174  }
175  PropertyAction { target: shape; property: "visible" }
176  }
177 
178  onRunningChanged: {
179  if (!running && state === "default" && image.nextSource !== "") {
180  image.source = image.nextSource;
181  image.nextSource = "";
182  }
183  }
184  }
185  ]
186 }