Olympic Stadium Tower With Special Lights In Early January 2012
During the beginning of 2012 there was a special light sculptures around Helsinki. This was one of them.

Pinching with GridView content in QML

Pinching in different contexts is essentially handled the same way. In most of the cases, the content which is to be interacted with, is placed inside the PinchArea element. This has been established already via two previous examples:

In the case of a view, such as GridView in this example, only the visible content is rendered. The delegate items which were visible earlier but moved outside the visible area of the given view, will be reset to their default state as can be seen via the second example below.

In case you would change the scaling or rotation of any item, then flick it outside the view, and once flicking back to that item, it has been set to its initial value. This is due data binding.

The first example shows using a PinchArea which contains the GridView. Scaling is separated in two different axis via trigonometry.

/* PinchingGridView.qml */
import QtQuick 1.1

Rectangle {
    id: main

    property real scalingX: 1
    property real scalingY: 1

    color: "#11262B"
    width: 480
    height: 848

    Component {
        id: gridDelegate
        Rectangle {
            width: gridArea.cellWidth
            height: gridArea.cellHeight
            color: Qt.rgba(Math.random(),
                Math.random(), Math.random(), 1)

            Text {
                anchors.centerIn: parent
                text: index
                font.pointSize: 14
                color: "snow"
            }

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    parent.color = Qt.rgba(Math.random(),
                        Math.random(), Math.random(), 1)
                }
            }
        }
    }

    PinchArea {
        property real initScaleX: 1
        property real initScaleY: 1

        anchors.fill: parent
        onPinchStarted: {
            initScaleX = main.scalingX;
            initScaleY = main.scalingY;
        }
        onPinchUpdated: {
            var radians = pinch.angle * Math.PI / 180;

            var scaleX = Math.abs(Math.cos(radians) * pinch.scale);
            var scaleY = Math.abs(Math.sin(radians) * pinch.scale);

            main.scalingX = scaleX * pinch.scale;
            main.scalingY = scaleY * pinch.scale;
        }

        GridView {
            id: gridArea
            anchors.fill: parent
            cellWidth: 120 * main.scalingX
            cellHeight: 80 * main.scalingY
            contentWidth: childrenRect.width
            contentHeight: childrenRect.height
            model: 200
            delegate: gridDelegate
        }
    }
}

As seen so far, only by placing the content, which might have mouse interaction, inside the PinchArea, can the pinch event be cancelled.

The second example shows how to handle PinchArea inside a cell.

/* PinchingGridViewCell.qml */
import QtQuick 1.1

Rectangle {
    id: main
    color: "#11262B"
    width: 480
    height: 848

    Component {
        id: gridDelegate
        Item {
            id: blockItem

            // Will reset to these values when outside visible area
            property real scaling: 1
            property real rotationing: -25
            property color fillColor: Qt.rgba(Math.random(),
                Math.random(), Math.random(), 1)

            width: gridArea.cellWidth
            height: gridArea.cellHeight

            Rectangle {
                width: parent.width * blockItem.scaling
                height: parent.height * blockItem.scaling
                anchors.centerIn: parent
                rotation: blockItem.rotationing
                transformOrigin: Item.Center
                color: blockItem.fillColor

                Text {
                    anchors.centerIn: parent
                    text: index
                    font.pointSize: 14
                    color: "snow"
                }
            }

            // Once pinch starts, the area is made bigger
            PinchArea {
                property real initRotation: 0
                property real initScale: 1

                anchors.fill: parent
                onPinchStarted: {
                    anchors.margins = -100
                    initRotation = blockItem.rotationing
                    initScale = blockItem.scaling
                }
                onPinchFinished: {
                    // last event if pinch
                    anchors.margins = 0
                    blockItem.z--;
                    redBorders.visible = false
                }
                onPinchUpdated: {
                    blockItem.scaling = initScale * pinch.scale
                    blockItem.rotationing = initRotation + pinch.rotation
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        blockItem.fillColor = Qt.rgba(Math.random(),
                            Math.random(), Math.random(), 1)
                    }
                    onPressed: {
                        // This is the first interaction to both pinch and mouse areas
                        blockItem.z++;
                        redBorders.visible = true
                    }
                    onReleased: {
                        // Last event if mouse
                        blockItem.z--;
                        redBorders.visible = false
                    }

                    // See where MouseArea is affecting
                    Rectangle {
                        id: redBorders
                        anchors.fill: parent
                        color: "transparent"
                        border.width: 4
                        border.color: "red"
                        opacity: 0.5
                        visible: parent.pressed || parent.parent.pinch.active
                    }

                }
            }
        }
    }

    GridView {
        id: gridArea
        anchors.fill: parent
        cellWidth: 200
        cellHeight: 120
        contentWidth: childrenRect.width
        contentHeight: childrenRect.height
        model: 2000
        delegate: gridDelegate
    }
}

Visibility of the red border inside mouse area is often visible if the view steals the mouse event from the mouse area.

Coming to Qt 5, we can forget about mixing MouseArea and PinchArea, and start using MultiPointTouchArea. Example available. Qt 5 is expected to be released later this Summer…