on xenial help sign in
Add zoomable image
commit2fd65f261957a9a35170d964a0f85ce3b4e16235 authorYing-Chun Liu <paul.liu@canonical.com> dateMon 24 Feb 2014, 22:30 (13 years ago) parentb792470
2 files changed+161−8
qml/Dash/Previews/PreviewZoomableImage.qml+109−8 tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+52
qml/Dash/Previews/PreviewZoomableImage.qml+109−8
@@ -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}
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+52
@@ -34,10 +34,16 @@ Rectangle {
3434 "zoomable": false
3535 }
3636
37+ property var widgetData2: {
38+ "source": "../graphics/phone/screenshots/gallery@12.png",
39+ "zoomable": true
40+ }
41+
3742 PreviewZoomableImage {
3843 id: zoomableImage
3944 width: parent.width
4045 widgetData: widgetData1
46+ anchors.fill: parent
4147 }
4248
4349 UT.UnityTestCase {
@@ -53,5 +59,51 @@ Rectangle {
5359 zoomableImage.widgetData = widgetData1;
5460 tryCompare(image.state, "ready");
5561 }
62+
63+ function test_zoomable() {
64+ var image = findChild(zoomableImage, "image");
65+
66+ zoomableImage.widgetData = widgetData2;
67+ waitForRendering(zoomableImage);
68+ tryCompare(image.state, "ready");
69+
70+ waitForRendering(image);
71+
72+ var oldScale = image.scale;
73+ var event1 = touchEvent();
74+ var event2 = touchEvent();
75+ var x1Start = zoomableImage.width*2/6;
76+ var y1Start = zoomableImage.height*2/6;
77+ var x1End = zoomableImage.width*1/6;
78+ var y1End = zoomableImage.height*1/6;
79+ var x2Start = zoomableImage.width*4/6;
80+ var y2Start = zoomableImage.height*4/6;
81+ var x2End = zoomableImage.width*5/6;
82+ var y2End = zoomableImage.height*5/6;
83+
84+ mouseMove(zoomableImage, zoomableImage.width/2, zoomableImage.height/2);
85+ mouseWheel(zoomableImage, zoomableImage.width/2, zoomableImage.height/2, 0, 10);
86+
87+ event1.press(0, x1Start, y1Start);
88+ event1.commit();
89+ event1.press(1, x2Start, y2Start);
90+ event1.commit();
91+
92+ for (var i=0.0; i<1.0; i+=0.02) {
93+ event1.move(0, x1Start+(x1End-x1Start)*i, y1Start+(y1End-y1Start)*i);
94+ event1.move(1, x2Start+(x2End-x2Start)*i, y2Start+(y2End-y2Start)*i);
95+ event1.commit();
96+ wait(30);
97+ }
98+
99+ event1.release(0, x1End, y1End);
100+ event1.commit();
101+ event1.release(1, x2End, y2End);
102+ event1.commit();
103+
104+ var newScale = image.scale;
105+ compare(newScale > oldScale, true, "the image should be larger than before");
106+
107+ }
56108 }
57109}