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 
40  state: "default"
41 
42  onSourceChanged: {
43  if (state === "ready") {
44  state = "default";
45  image.nextSource = source;
46  } else {
47  image.source = source;
48  }
49  }
50 
51  UbuntuShape {
52  id: placeholder
53  objectName: "placeholder"
54  color: "#22FFFFFF"
55  anchors.fill: shape
56  visible: opacity != 0
57 
58  ActivityIndicator {
59  id: activity
60  anchors.centerIn: parent
61  opacity: 0
62  visible: opacity != 0
63 
64  running: visible
65  }
66 
67  Image {
68  id: errorImage
69  objectName: "errorImage"
70  anchors.centerIn: parent
71  opacity: 0
72  visible: opacity != 0
73 
74  source: "graphics/close.png"
75  sourceSize { width: units.gu(3); height: units.gu(3) }
76  }
77  }
78 
79  UbuntuShape {
80  id: shape
81  objectName: "shape"
82  height: root.initialHeight
83  width: root.initialWidth
84  anchors.centerIn: root.scaleTo == "fit" ? parent : undefined
85 
86  opacity: 0
87  visible: opacity != 0
88 
89  image: Image {
90  id: image
91  objectName: "image"
92 
93  property url nextSource
94  property string format: image.implicitWidth > image.implicitHeight ? "landscape" : "portrait"
95 
96  fillMode: Image.PreserveAspectFit
97  asynchronous: true
98  cache: false
99  horizontalAlignment: Image.AlignHCenter
100  verticalAlignment: Image.AlignVCenter
101  sourceSize.width: root.scaleTo == "width" ? root.width
102  : root.scaleTo == "fit" && root.width <= root.height ? root.width
103  : 0
104  sourceSize.height: root.scaleTo == "height" ? root.height
105  : root.scaleTo == "fit" && root.height <= root.width ? root.height
106  : 0
107  }
108  }
109 
110  states: [
111  State {
112  name: "default"
113  when: image.source == ""
114  PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
115  PropertyChanges { target: errorImage; opacity: 0 }
116  },
117  State {
118  name: "loading"
119  extend: "default"
120  when: image.status === Image.Loading
121  PropertyChanges { target: activity; opacity: 1 }
122  },
123  State {
124  name: "ready"
125  when: image.status === Image.Ready && image.source != ""
126  PropertyChanges { target: root; implicitWidth: shape.width; implicitHeight: shape.height }
127  PropertyChanges { target: placeholder; opacity: 0 }
128  PropertyChanges { target: shape; opacity: 1
129  width: root.scaleTo == "width" || (root.scaleTo == "fit" && image.format == "landscape") ? root.width
130  : root.scaleTo == "" ? image.implicitWidth : image.implicitWidth * height / image.implicitHeight
131  height: root.scaleTo == "height" || (root.scaleTo == "fit" && image.format == "portrait") ? root.height
132  : root.scaleTo == "" ? image.implicitHeight : image.implicitHeight * width / image.implicitWidth
133  }
134  },
135  State {
136  name: "error"
137  extend: "default"
138  when: image.status === Image.Error
139  PropertyChanges { target: errorImage; opacity: 1.0 }
140  }
141  ]
142 
143  transitions: [
144  Transition {
145  to: "ready"
146  objectName: "readyTransition"
147  SequentialAnimation {
148  PropertyAction { target: shape; property: "visible" }
149  ParallelAnimation {
150  NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
151  UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
152  UbuntuNumberAnimation { target: shape; properties: "width,height" }
153  NumberAnimation {
154  targets: [placeholder, activity, errorImage]; property: "opacity";
155  easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
156  }
157  }
158  }
159  },
160 
161  Transition {
162  to: "*"
163  objectName: "genericTransition"
164  SequentialAnimation {
165  ParallelAnimation {
166  NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
167  NumberAnimation {
168  targets: [placeholder, activity, errorImage]; property: "opacity";
169  easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
170  }
171  UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
172  UbuntuNumberAnimation { target: shape; properties: "width,height" }
173  }
174  PropertyAction { target: shape; property: "visible" }
175  }
176 
177  onRunningChanged: {
178  if (!running && state === "default" && image.nextSource !== "") {
179  image.source = image.nextSource;
180  image.nextSource = "";
181  }
182  }
183  }
184  ]
185 }