on 239fdcc help sign in
unity8/qml/Components/LazyImage.qml
198 lines 7.1 kB history raw
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 */
20import QtQuick 2.4
21import Ubuntu.Components 1.3
23Item {
24 id: root
26 property url source
27 // TODO convert into enums when available in QML
28 property string scaleTo
30 property real initialWidth: scaleTo == "width" || scaleTo == "fit" ? width : units.gu(10)
31 property real initialHeight: scaleTo == "height" || scaleTo == "fit" ? height : units.gu(10)
33 property alias sourceSize: image.sourceSize
34 property alias asynchronous: image.asynchronous
35 property alias cache: image.cache
36 property alias sourceImage: image
38 property bool useUbuntuShape: true
39 property bool pressed: false
41 state: "default"
43 onSourceChanged: {
44 if (state === "ready") {
45 state = "default";
46 image.nextSource = source;
47 } else {
48 image.source = source;
49 }
50 }
52 Loader {
53 id: placeholder
54 objectName: "placeholder"
55 anchors.fill: shape
56 active: useUbuntuShape
57 visible: opacity != 0
58 sourceComponent: UbuntuShape {
59 backgroundColor: "#22FFFFFF"
60 }
62 ActivityIndicator {
63 id: activity
64 anchors.centerIn: parent
65 opacity: 0
66 visible: opacity != 0
68 running: visible
69 }
71 Image {
72 id: errorImage
73 objectName: "errorImage"
74 anchors.centerIn: parent
75 opacity: 0
76 visible: opacity != 0
78 source: "graphics/close.png"
79 sourceSize { width: units.gu(3); height: units.gu(3) }
80 }
81 }
83 Loader {
84 id: shape
85 objectName: "shape"
86 height: root.initialHeight
87 width: root.initialWidth
88 anchors.centerIn: root.scaleTo == "fit" ? parent : undefined
89 active: useUbuntuShape
90 opacity: 0
91 visible: opacity != 0
92 sourceComponent: UbuntuShapeOverlay {
93 property bool pressed: false
94 overlayColor: Qt.rgba(0, 0, 0, pressed ? 0.1 : 0)
95 overlayRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
96 }
97 onLoaded: {
98 item.source = image;
99 item.pressed = Qt.binding(function() { return root.pressed; });
100 }
102 Image {
103 id: image
104 objectName: "image"
106 property url nextSource
107 property string format: image.implicitWidth > image.implicitHeight ? "landscape" : "portrait"
109 anchors.fill: parent
110 visible: !useUbuntuShape
111 fillMode: Image.PreserveAspectFit
112 asynchronous: true
113 cache: false
114 sourceSize.width: root.scaleTo == "width" ? root.width
115 : root.scaleTo == "fit" && root.width <= root.height ? root.width
116 : 0
117 sourceSize.height: root.scaleTo == "height" ? root.height
118 : root.scaleTo == "fit" && root.height <= root.width ? root.height
119 : 0
120 }
121 }
123 states: [
124 State {
125 name: "default"
126 when: image.source == ""
127 PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
128 PropertyChanges { target: errorImage; opacity: 0 }
129 },
130 State {
131 name: "loading"
132 extend: "default"
133 when: image.status === Image.Loading
134 PropertyChanges { target: activity; opacity: 1 }
135 },
136 State {
137 name: "ready"
138 when: image.status === Image.Ready && image.source != ""
139 PropertyChanges { target: root; implicitWidth: shape.width; implicitHeight: shape.height }
140 PropertyChanges { target: placeholder; opacity: 0 }
141 PropertyChanges { target: shape; opacity: 1
142 width: root.scaleTo == "width" || (root.scaleTo == "fit" && image.format == "landscape") ? root.width
143 : root.scaleTo == "" ? image.implicitWidth : image.implicitWidth * height / image.implicitHeight
144 height: root.scaleTo == "height" || (root.scaleTo == "fit" && image.format == "portrait") ? root.height
145 : root.scaleTo == "" ? image.implicitHeight : image.implicitHeight * width / image.implicitWidth
146 }
147 },
148 State {
149 name: "error"
150 extend: "default"
151 when: image.status === Image.Error
152 PropertyChanges { target: errorImage; opacity: 1.0 }
153 }
154 ]
156 transitions: [
157 Transition {
158 to: "ready"
159 objectName: "readyTransition"
160 SequentialAnimation {
161 PropertyAction { target: shape; property: "visible" }
162 ParallelAnimation {
163 NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
164 UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
165 UbuntuNumberAnimation { target: shape; properties: "width,height" }
166 NumberAnimation {
167 targets: [placeholder, activity, errorImage]; property: "opacity";
168 easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
169 }
170 }
171 }
172 },
174 Transition {
175 to: "*"
176 objectName: "genericTransition"
177 SequentialAnimation {
178 ParallelAnimation {
179 NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
180 NumberAnimation {
181 targets: [placeholder, activity, errorImage]; property: "opacity";
182 easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
183 }
184 UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
185 UbuntuNumberAnimation { target: shape; properties: "width,height" }
186 }
187 PropertyAction { target: shape; property: "visible" }
188 }
190 onRunningChanged: {
191 if (!running && state === "default" && image.nextSource !== "") {
192 image.source = image.nextSource;
193 image.nextSource = "";
194 }
195 }
196 }
197 ]