From 1574ba82e6a3dae03fc129973da1da9b0f6a5543 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 4 Dec 2014 15:35:40 +0100 Subject: Photosurface example: flickable surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Flickable provides a way of testing interaction with 2-finger trackpad gestures: if the cursor is over the background, you can flick the surface via wheel events (which come from native flick gestures if you are using a trackpad on OS X); inside the bounds of a photo, the same 2-finger gesture is for zooming and rotating. Also, random position and rotation are applied more correctly, and only at startup. Position and rotation changes are animated. Change-Id: Iab49b7f2e99a9686424368fd94f0b7f89807da22 Reviewed-by: Morten Johan Sørvig --- examples/quick/demos/photosurface/photosurface.qml | 168 +++++++++++++-------- 1 file changed, 107 insertions(+), 61 deletions(-) (limited to 'examples') diff --git a/examples/quick/demos/photosurface/photosurface.qml b/examples/quick/demos/photosurface/photosurface.qml index 6c85bef77f..96478ebf65 100644 --- a/examples/quick/demos/photosurface/photosurface.qml +++ b/examples/quick/demos/photosurface/photosurface.qml @@ -37,7 +37,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.4 import QtQuick.Dialogs 1.0 import QtQuick.Window 2.1 import Qt.labs.folderlistmodel 1.0 @@ -50,6 +50,7 @@ Window { property int highestZ: 0 property real defaultSize: 200 property var currentFrame: undefined + property real surfaceViewportRatio: 1.5 FileDialog { id: fileDialog @@ -58,76 +59,121 @@ Window { onAccepted: folderModel.folder = fileUrl + "/" } - Repeater { - model: FolderListModel { - id: folderModel - objectName: "folderModel" - showDirs: false - nameFilters: ["*.png", "*.jpg", "*.gif"] - } - Rectangle { - id: photoFrame - width: image.width * (1 + 0.10 * image.height / image.width) - height: image.height * 1.10 - scale: defaultSize / Math.max(image.sourceSize.width, image.sourceSize.height) - border.color: "black" - border.width: 2 - smooth: true - antialiasing: true - Component.onCompleted: { - x = Math.random() * root.width - defaultSize - y = Math.random() * root.height - defaultSize - rotation = Math.random() * 13 - 6 + Flickable { + id: flick + anchors.fill: parent + contentWidth: width * surfaceViewportRatio + contentHeight: height * surfaceViewportRatio + Repeater { + model: FolderListModel { + id: folderModel + objectName: "folderModel" + showDirs: false + nameFilters: ["*.png", "*.jpg", "*.gif"] } - Image { - id: image - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - source: folderModel.folder + fileName + Rectangle { + id: photoFrame + width: image.width * (1 + 0.10 * image.height / image.width) + height: image.height * 1.10 + scale: defaultSize / Math.max(image.sourceSize.width, image.sourceSize.height) + Behavior on scale { NumberAnimation { duration: 200 } } + Behavior on x { NumberAnimation { duration: 200 } } + Behavior on y { NumberAnimation { duration: 200 } } + border.color: "black" + border.width: 2 + smooth: true antialiasing: true - } - PinchArea { - anchors.fill: parent - pinch.target: photoFrame - pinch.minimumRotation: -360 - pinch.maximumRotation: 360 - pinch.minimumScale: 0.1 - pinch.maximumScale: 10 - onPinchStarted: setFrameColor(); - MouseArea { - id: dragArea - hoverEnabled: true + Component.onCompleted: { + x = Math.random() * root.width - width / 2 + y = Math.random() * root.height - height / 2 + rotation = Math.random() * 13 - 6 + } + Image { + id: image + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: folderModel.folder + fileName + antialiasing: true + } + PinchArea { anchors.fill: parent - drag.target: photoFrame - onPressed: { - photoFrame.z = ++root.highestZ; - parent.setFrameColor(); - } - onEntered: parent.setFrameColor(); - onWheel: { - if (wheel.modifiers & Qt.ControlModifier) { - photoFrame.rotation += wheel.angleDelta.y / 120 * 5; - if (Math.abs(photoFrame.rotation) < 4) - photoFrame.rotation = 0; - } else { - photoFrame.rotation += wheel.angleDelta.x / 120; - if (Math.abs(photoFrame.rotation) < 0.6) - photoFrame.rotation = 0; - var scaleBefore = photoFrame.scale; - photoFrame.scale += photoFrame.scale * wheel.angleDelta.y / 120 / 10; + pinch.target: photoFrame + pinch.minimumRotation: -360 + pinch.maximumRotation: 360 + pinch.minimumScale: 0.1 + pinch.maximumScale: 10 + pinch.dragAxis: Pinch.XAndYAxis + onPinchStarted: setFrameColor(); + MouseArea { + id: dragArea + hoverEnabled: true + anchors.fill: parent + drag.target: photoFrame + scrollGestureEnabled: false // 2-finger-flick gesture should pass through to the Flickable + onPressed: { + photoFrame.z = ++root.highestZ; + parent.setFrameColor(); + } + onEntered: parent.setFrameColor(); + onWheel: { + if (wheel.modifiers & Qt.ControlModifier) { + photoFrame.rotation += wheel.angleDelta.y / 120 * 5; + if (Math.abs(photoFrame.rotation) < 4) + photoFrame.rotation = 0; + } else { + photoFrame.rotation += wheel.angleDelta.x / 120; + if (Math.abs(photoFrame.rotation) < 0.6) + photoFrame.rotation = 0; + var scaleBefore = photoFrame.scale; + photoFrame.scale += photoFrame.scale * wheel.angleDelta.y / 120 / 10; + } } } - } - function setFrameColor() { - if (currentFrame) - currentFrame.border.color = "black"; - currentFrame = photoFrame; - currentFrame.border.color = "red"; + function setFrameColor() { + if (currentFrame) + currentFrame.border.color = "black"; + currentFrame = photoFrame; + currentFrame.border.color = "red"; + } } } } } + Rectangle { + id: verticalScrollDecorator + anchors.right: parent.right + anchors.margins: 2 + color: "cyan" + border.color: "black" + border.width: 1 + width: 5 + radius: 2 + antialiasing: true + height: flick.height * (flick.height / flick.contentHeight) - (width - anchors.margins) * 2 + y: flick.contentY * (flick.height / flick.contentHeight) + NumberAnimation on opacity { id: vfade; to: 0; duration: 500 } + onYChanged: { opacity = 1.0; fadeTimer.restart() } + } + + Rectangle { + id: horizontalScrollDecorator + anchors.bottom: parent.bottom + anchors.margins: 2 + color: "cyan" + border.color: "black" + border.width: 1 + height: 5 + radius: 2 + antialiasing: true + width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 + x: flick.contentX * (flick.width / flick.contentWidth) + NumberAnimation on opacity { id: hfade; to: 0; duration: 500 } + onXChanged: { opacity = 1.0; fadeTimer.restart() } + } + + Timer { id: fadeTimer; interval: 1000; onTriggered: { hfade.start(); vfade.start() } } + Image { anchors.top: parent.top anchors.left: parent.left -- cgit v1.2.3