Hi Shawn,

I've realized it might be faster to provide some code than try to
explain better.

Original.txt - is the code where scaling happens relatively top/left
Approach_1.txt - adjusting x/y
Approach_2.txt - scaling top level item & scaling non-zoomable to compensate

>> anchors.centerIn: parent

What I meant is rather anchors.centerIn: child (so that child would
free-zoom relatively center, and parent would center itself relatively
center of the child)
чт, 13 сент. 2018 г. в 16:15, Shawn Rutledge <shawn.rutle...@qt.io>:
>
>
> > On 13 Sep 2018, at 14:41, Alexander Ivash <elder...@gmail.com> wrote:
> >
> > I need pinch-zoomable item container with non-zoomable item container
> > attached to the bottom. Like this:
> >
> > Item {
> >   id: item
> >   Item {
> >     id: zoomable
> >    }
> >
> >   Item {
> >     id: nonzoomable
> >   }
> > }
> >
> > (anchoring, geometry omitted for simplicity)
> >
> > I see at least the following solutions:
> >
> > 1. Change 'scale' of the whole item (zoomable + non-zoomable), then
> > change 'scale' of non-zoomable to compensate parent scaling. It feels
> > a bit wrong so I'd like to avoid it. Also doing in this way leads to
> > some issues with anchoring non-zoomable item to zoomable one properly.
> >
> > 2. Change 'scale' of the zoomable part only. But in this case I need
> > to adjust x/y of 'item', otherwise scaling will always be happening
> > relatively top/left (and I need relatively to the center)
>
> PinchArea only sets the scale property of the zoomable item directly, and 
> that is relative to the Item transformOrigin which defaults to center.
>
> PinchHandler zooms relative to the centroid between the touchpoints, which is 
> more typical behavior like what you get in most non-Qt interfaces (you need 
> to be able to zoom into a particular geographical area of a map, or an 
> interesting part of some drawing, for example).  It normally does that by 
> setting the scale and the x and y properties at the same time.  But it’s not 
> overriding anchors.centerIn: parent, so you can still use that to keep your 
> item centered.
>
> If yours is always zooming toward the top left, it must be because of your 
> anchors or bindings, or because of setting  transformOrigin to TopLeft.
>
> You could use another wrapper item to hold the place in the layout, and then 
> add your zoomable item to that.  If it has no bindings or anchors, it can be 
> free to zoom and move around within that space.  If you want to disable 
> movement, or allow movement only within certain confines, you can try the 
> minimumX/Y and maximumX/Y properties.
>
> > Is there better way to do it?
> >
> > If there would be a way to center parent in child - I could anchor
> > 'item' to the center of 'zoomable' and everything would work
> > magically. But such kinds of anchors are not supported.
>
> anchors.centerIn: parent
>
> What I sometimes wish we had is _bindable_ centerX/Y properties.  But at 
> least we have anchors.
>
import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Shapes 1.0
import Qt.labs.handlers 1.0

Item {
    id: draggableObject

    property int index: -1
    default property alias content: content.children

    signal grabChanged(var index);
    signal tapped(var index);

    width: contentContainer.width
    onWidthChanged: {
        console.debug('draggable width: ', width);
    }

    height: contentContainer.height
    onHeightChanged: {
        console.debug('draggable height: ', height);
    }

    Item {
        id: contentContainer
        width: content.width * content.scale
        property int prevWidth: width
        onWidthChanged: {
            console.debug('content width: ', width);
            draggableObject.x -= (width - prevWidth) / 2
            prevWidth = width;
        }

        height: content.height * content.scale
        property int prevHeight: height
        onHeightChanged: {
            console.debug('content height: ', height);
            draggableObject.y -= (height - prevHeight) / 2
            prevHeight = height;
        }

        DragHandler {
            onGrabChanged: {
                draggableObject.grabChanged(index);
            }
        }

        PinchHandler {
            target: content
        }

        TapHandler {
            onTapped: {
                draggableObject.tapped(index);
            }
        }

        Item {
            id: content
            anchors.centerIn: parent
            clip: true

            width: childrenRect.width
            onWidthChanged: {
                console.debug('content width: ', width);
            }

            height: childrenRect.height
            onHeightChanged: {
                console.debug('content height: ', height);
            }

            onScaleChanged: {
            }
        }

        Shape {
            anchors.centerIn: parent
            width: contentContainer.width
            height: contentContainer.height

            ShapePath {
                fillColor: 'transparent'
                strokeColor: 'green'
                strokeWidth: 4
                strokeStyle: ShapePath.DashLine
                startX: 0
                startY: 0
                dashPattern: [ 1, 4 ]
                PathLine { x: contentContainer.width; y: 0 }
                PathLine { x: contentContainer.width; y: 
contentContainer.height }
                PathLine { x: 0; y: contentContainer.height }
                PathLine { x: 0; y: 0 }
            }
        }

        MouseArea {
            id: mouseZoomer
            anchors.fill: parent
            hoverEnabled: false
            onPressed: {
                mouse.accepted = false
            }
            onReleased: {
                mouse.accepted = false
            }

            onWheel: {
                if(wheel.modifiers & Qt.ControlModifier) {
                    console.debug('onWheel');
                    if(wheel.angleDelta.y > 1.0) {
                        content.scale *= 1.1
                    } else {
                        content.scale /= 1.1
                    }
                } else {
                    wheel.accepted = false
                }
            }
        }
    }

    Button {
        anchors.top: contentContainer.bottom
        anchors.right: contentContainer.right

        width: 50
        height: 50
        text: 'button: ' + index
    }
}
import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Shapes 1.0
import Qt.labs.handlers 1.0

Item {
    id: draggableObject

    property int index: -1
    default property alias content: content.children

    signal grabChanged(var index);
    signal tapped(var index);

    width: contentContainer.width
    onWidthChanged: {
        console.debug('draggable width: ', width);
    }

    height: contentContainer.height
    onHeightChanged: {
        console.debug('draggable height: ', height);
    }

    Item {
        id: contentContainer
        width: content.width * content.scale
        property int prevWidth: width
        onWidthChanged: {
            console.debug('content width: ', width);
        }

        height: content.height * content.scale
        property int prevHeight: height
        onHeightChanged: {
            console.debug('content height: ', height);
        }

        DragHandler {
            onGrabChanged: {
                draggableObject.grabChanged(index);
            }
        }

        PinchHandler {
            target: draggableObject
        }

        TapHandler {
            onTapped: {
                draggableObject.tapped(index);
            }
        }

        Item {
            id: content
            anchors.centerIn: parent
            clip: true

            width: childrenRect.width
            onWidthChanged: {
                console.debug('content width: ', width);
            }

            height: childrenRect.height
            onHeightChanged: {
                console.debug('content height: ', height);
            }

            onScaleChanged: {
            }
        }

        Shape {
            anchors.centerIn: parent
            width: contentContainer.width
            height: contentContainer.height

            ShapePath {
                fillColor: 'transparent'
                strokeColor: 'green'
                strokeWidth: 4
                strokeStyle: ShapePath.DashLine
                startX: 0
                startY: 0
                dashPattern: [ 1, 4 ]
                PathLine { x: contentContainer.width; y: 0 }
                PathLine { x: contentContainer.width; y: 
contentContainer.height }
                PathLine { x: 0; y: contentContainer.height }
                PathLine { x: 0; y: 0 }
            }
        }

        MouseArea {
            id: mouseZoomer
            anchors.fill: parent
            hoverEnabled: false
            onPressed: {
                mouse.accepted = false
            }
            onReleased: {
                mouse.accepted = false
            }

            onWheel: {
                if(wheel.modifiers & Qt.ControlModifier) {
                    console.debug('onWheel');
                    if(wheel.angleDelta.y > 1.0) {
                        draggableObject.scale *= 1.1
                    } else {
                        draggableObject.scale /= 1.1
                    }
                } else {
                    wheel.accepted = false
                }
            }
        }
    }

    Button {
        anchors.top: contentContainer.bottom
        anchors.right: contentContainer.right
        scale: 1 / draggableObject.scale

        width: 50
        height: 50
        text: 'button: ' + index
    }
}
import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Shapes 1.0
import Qt.labs.handlers 1.0

Item {
    id: draggableObject

    property int index: -1
    default property alias content: content.children

    signal grabChanged(var index);
    signal tapped(var index);

    width: contentContainer.width
    onWidthChanged: {
        console.debug('draggable width: ', width);
    }

    height: contentContainer.height
    onHeightChanged: {
        console.debug('draggable height: ', height);
    }

    Item {
        id: contentContainer
        width: content.width * content.scale

        height: content.height * content.scale

        DragHandler {
            onGrabChanged: {
                draggableObject.grabChanged(index);
            }
        }

        PinchHandler {
            target: content
        }

        TapHandler {
            onTapped: {
                draggableObject.tapped(index);
            }
        }

        Item {
            id: content
            anchors.centerIn: parent
            clip: true

            width: childrenRect.width
            onWidthChanged: {
                console.debug('content width: ', width);
            }

            height: childrenRect.height
            onHeightChanged: {
                console.debug('content height: ', height);
            }

            onScaleChanged: {
            }
        }

        Shape {
            anchors.centerIn: parent
            width: contentContainer.width
            height: contentContainer.height

            ShapePath {
                fillColor: 'transparent'
                strokeColor: 'green'
                strokeWidth: 4
                strokeStyle: ShapePath.DashLine
                startX: 0
                startY: 0
                dashPattern: [ 1, 4 ]
                PathLine { x: contentContainer.width; y: 0 }
                PathLine { x: contentContainer.width; y: 
contentContainer.height }
                PathLine { x: 0; y: contentContainer.height }
                PathLine { x: 0; y: 0 }
            }
        }

        MouseArea {
            id: mouseZoomer
            anchors.fill: parent
            hoverEnabled: false
            onPressed: {
                mouse.accepted = false
            }
            onReleased: {
                mouse.accepted = false
            }

            onWheel: {
                if(wheel.modifiers & Qt.ControlModifier) {
                    console.debug('onWheel');
                    if(wheel.angleDelta.y > 1.0) {
                        content.scale *= 1.1
                    } else {
                        content.scale /= 1.1
                    }
                } else {
                    wheel.accepted = false
                }
            }
        }
    }

    Button {
        anchors.top: contentContainer.bottom
        anchors.right: contentContainer.right

        width: 50
        height: 50
        text: 'button: ' + index
    }
}
_______________________________________________
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest

Reply via email to