@@ -28,14 +28,115 @@ PreviewWidget {
2828 id: root
2929 implicitHeight: units.gu(22)
3030
31− LazyImage {
32− objectName: "image"
33− anchors {
34− top: parent.top
35− bottom: parent.bottom
31+ Flickable {
32+ id: flickable
33+ objectName: "flickable"
34+ clip: true
35+ contentHeight: imageContainer.height
36+ contentWidth: imageContainer.width
37+ onHeightChanged: image.calculateSize()
38+ onWidthChanged: image.calculateSize()
39+ anchors.fill: parent
40+
41+ Item {
42+ id: imageContainer
43+ objectName: "imageContainer"
44+ width: Math.max(image.width * image.scale, flickable.width)
45+ height: Math.max(image.height * image.scale, flickable.height)
46+
47+ AnimatedImage {
48+ id: image
49+ objectName: "image"
50+ property real prevScale
51+ smooth: !flickable.movingVertically
52+ anchors.centerIn: parent
53+ fillMode: Image.PreserveAspectFit
54+ source: widgetData["source"]
55+
56+ function calculateSize() {
57+ scale = Math.min(flickable.width / width, flickable.height / height) * 0.98;
58+ pinchArea.minScale = scale;
59+ prevScale = Math.min(scale, 1);
60+ }
61+
62+ onScaleChanged: {
63+ if ((width * scale) > flickable.width) {
64+ var xoff = (flickable.width / 2 + flickable.contentX) * scale / prevScale;
65+ flickable.contentX = xoff - flickable.width / 2;
66+ }
67+ if ((height * scale) > flickable.height) {
68+ var yoff = (flickable.height / 2 + flickable.contentY) * scale / prevScale;
69+ flickable.contentY = yoff - flickable.height / 2;
70+ }
71+
72+ prevScale = scale;
73+ }
74+
75+ onStatusChanged: {
76+ if (status == Image.Ready) {
77+ calculateSize();
78+ playing = true;
79+ }
80+ }
81+ }
82+ }
83+
84+ PinchArea {
85+ id: pinchArea
86+ objectName: "pinchArea"
87+ property real minScale: 1.0
88+ property real lastScale: 1.0
89+ anchors.fill: parent
90+ enabled: widgetData["zoomable"] ? widgetData["zoomable"] : false
91+
92+ pinch.target: image
93+ pinch.minimumScale: minScale
94+
95+ onPinchFinished: flickable.returnToBounds()
96+ }
97+
98+ MouseArea {
99+ id: mouseArea
100+ objectName: "mouseArea"
101+
102+ anchors.fill: parent
103+ property bool doubleClicked: false
104+ property bool swipeDone: false
105+ property int startX
106+ property int startY
107+ property real startScale: pinchArea.minScale
108+ enabled: widgetData["zoomable"] ? widgetData["zoomable"] : false
109+
110+ onWheel: {
111+ if (wheel.angleDelta.y > 0) {
112+ startScale = image.scale;
113+ image.scale = startScale + 0.1;
114+ } else if (wheel.angleDelta.y < 0) {
115+ startScale = image.scale;
116+ if (image.scale > 0.1) {
117+ image.scale = startScale - 0.1;
118+ }
119+ }
120+ wheel.accepted = true;
121+ }
122+
123+ onPressed: {
124+ startX = (mouse.x / image.scale);
125+ startY = (mouse.y / image.scale);
126+ startScale = image.scale;
127+ }
128+
129+ onReleased: {
130+ if (image.scale == startScale) {
131+ var deltaX = (mouse.x / image.scale) - startX;
132+ var deltaY = (mouse.y / image.scale) - startY;
133+
134+ if (image.scale == pinchArea.minScale &&
135+ (Math.abs(deltaX) > 50 || Math.abs(deltaY) > 50)) {
136+ swipeDone = true;
137+ }
138+ }
139+ }
36140 }
37− scaleTo: "height"
38− source: widgetData["source"]
39− initialWidth: units.gu(13)
40141 }
41142}