Assuming no anchoring is set over our target Rectangle, you have a set of options to achieve what you want.
1. States and transitions
In this approach you define just one State: the expanded one. The other State is the default one, i.e. the State in which the Rectangle only covers a small portion of the window. A Transition is applied without from and to so that it is applied both when the Rectangle is expanded or shrunk down. Thanks to States, we do not need to store previous coordinates as their values are restored when the default state is set back. Note that, in the following example, I've removed the Math.random() from x and y to avoid reevaluation and assignment of random coordinates every time we get back from "EXPANDED" state. Here is the code:
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
id: win
title: qsTr("Playground")
width: 620
height: 420
visible: true
Rectangle {
id: rect
width: 20
height: 20
color: "black"
MouseArea {
anchors.fill: parent
onDoubleClicked: {
rect.state = rect.state === "EXPANDED" ? "" : "EXPANDED"
}
}
states: [
State {
name: "EXPANDED"
PropertyChanges { target: rect; x: 0}
PropertyChanges { target: rect; y: 0}
PropertyChanges { target: rect; width: parent.width}
PropertyChanges { target: rect; height: parent.height}
}
]
transitions: [
Transition {
ParallelAnimation {
NumberAnimation { target: rect; property: "x"; duration: 350 }
NumberAnimation { target: rect; property: "y"; duration: 350 }
NumberAnimation { target: rect; property: "width"; duration: 350}
NumberAnimation { target: rect; property: "height"; duration: 350}
}
}
]
// randomization is applied with JS --> no properties binding
Component.onCompleted: {
rect.x = Math.random() * 600
rect.y = Math.random() * 400
}
}
}
2. Animations
Simply put, define an animation to expand the Rectangle and one to shrink it down. Then call one or another depending on the position/size/whatever. You can write something like this:
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
id: win
title: qsTr("Playground")
width: 620
height: 420
visible: true
Rectangle {
id: rect
x: Math.random() * 600
y: Math.random() * 400
property int oldx; property int oldy
width: 20
height: 20
color: "black"
MouseArea {
anchors.fill: parent
onDoubleClicked: {
if(rect.x === 0){
shrink.start()
} else {
rect.oldx = rect.x
rect.oldy = rect.y
expand.start()
}
}
}
ParallelAnimation {
id: shrink
NumberAnimation { target: rect; property: "x"; to: rect.oldx; duration: 350 }
NumberAnimation { target: rect; property: "y"; to: rect.oldy; duration: 350 }
NumberAnimation { target: rect; property: "width"; to: 20; duration: 350}
NumberAnimation { target: rect; property: "height"; to: 20; duration: 350}
}
ParallelAnimation {
id: expand
NumberAnimation { target: rect; property: "x"; to: 0; duration: 350 }
NumberAnimation { target: rect; property: "y"; to: 0; duration: 350 }
NumberAnimation { target: rect; property: "width"; to: win.width; duration: 350}
NumberAnimation { target: rect; property: "height"; to: win.height; duration: 350}
}
}
}
3. Behaviors
A Behavior defines a default animation for a property change. In this approach we define an homogeneous set of animations for the different properties involved (x, y, width and height). In this way we only need to update the properties to the correct values, leaving to the Behaviors the task to animate the change. You can write something like this:
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
id: win
title: qsTr("Playground")
width: 620
height: 420
visible: true
Rectangle {
id: rect
x: Math.random() * 600
y: Math.random() * 400
property int oldx; property int oldy
width: 20
height: 20
color: "black"
MouseArea {
anchors.fill: parent
onDoubleClicked: {
if(rect.x === 0){
rect.x = rect.oldx
rect.y = rect.oldy
rect.width = rect.height = 20
} else {
rect.oldx = rect.x
rect.oldy = rect.y
rect.x = rect.y = 0
rect.width = win.width
rect.height = win.height
}
}
}
Behavior on x {
NumberAnimation { duration: 450 }
}
Behavior on y {
NumberAnimation { duration: 450 }
}
Behavior on width {
NumberAnimation { duration: 450 }
}
Behavior on height {
NumberAnimation { duration: 450 }
}
}
}
The first approach is, by far, the cleaner solution of all since it does not involve the usage of temp variables, like the second and third. States automatically save/restore the status of the variables as the component moves among them.