Hi everyone

Here is the thing - I'm planning to release a cards game soon (regular patience games like Solitaire, Freecell etc.) developped with QtQuick and C++ on SailfishOS. I have a small problem when I want to animate nicely my cards. I use dynamical binding of anchors.top and anchors.left properties on my QML Card objects; indeed, the top anchor of a given card is the top anchor of its parent card on the stack (or the top anchor of the stack if the card is alone on a tableau), same goes for the left anchor. When dragging a card begins, the JS binding in Card sets these anchors to "undefined" to be able to freely drag the card wherever you want. Also, in y Card properties, I put a behavior on anchors.left and anchors.right to animate the anchor changes with AnchorAnimation.

Here is the part of Card.qml that is interesting:
Qt Code:
  1. Flipable {
  2. id: card
  3. property int cid
  4. property QtObject parentCard
  5. property QtObject parentStack
  6. property bool isValueShown
  7. property bool isHint
  8. property bool canMove
  9. property bool dragged: false
  10.  
  11.  
  12. Drag.active: dragArea.drag.active
  13. Drag.hotSpot.x: width / 2
  14. Drag.hotSpot.y: height / 2
  15.  
  16. Behavior on anchors.top { AnchorAnimation { duration: 1000 } }
  17. Behavior on anchors.left { AnchorAnimation { duration: 1000 } }
  18.  
  19. function aParentIsDragged() {
  20. // returns true if any ancestor is being dragged, false otherwise
  21. }
  22.  
  23. height: 150
  24. width: height * 0.7333
  25.  
  26. back: Rectangle {
  27. anchors.fill: parent
  28.  
  29. // card back graphics...
  30. }
  31.  
  32. front: DropArea {
  33. enabled: !(!isValueShown || dragged || aParentIsDragged())
  34.  
  35. anchors.fill: parent
  36. onDropped: {
  37. gameInterface.move(drag.source.cid, parentStack.id)
  38. }
  39.  
  40. // only card graphics here...
  41. }
  42.  
  43. transform: Rotation {
  44. id: rotation
  45. origin.x: card.width / 2.0
  46. origin.y: card.height / 2.0
  47. axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis
  48. angle: -180 // the default angle
  49. }
  50.  
  51. states: [
  52. State {
  53. name: "visible"
  54. when: card.isValueShown
  55.  
  56. PropertyChanges {
  57. target: rotation
  58. angle: 0
  59. }
  60. }
  61. ]
  62.  
  63. transitions: Transition {
  64. NumberAnimation { target: rotation; property: "angle"; duration: 75 }
  65. }
  66.  
  67. MouseArea {
  68. enabled: canMove
  69. id: dragArea
  70. anchors.fill: parent
  71. drag.target: parent
  72. onPressed: dragged = true
  73. onCanceled: dragged = false
  74. onReleased: {
  75. parent.Drag.drop()
  76. dragged = false
  77. }
  78.  
  79. }
  80. }
To copy to clipboard, switch view to plain text mode 

And here the part of Solitaire.qml generating the cards:
Qt Code:
  1. Repeater {
  2. id: cards
  3. property bool ready: false
  4.  
  5. model: gameInterface.cards
  6. delegate: Card {
  7. cid: modelData.id
  8. parentCard: modelData.parent
  9. parentStack: modelData.cardStack
  10.  
  11. value: modelData.value
  12. color: modelData.color
  13. isValueShown: modelData.isVisible
  14. isHint: modelData.isHint
  15. canMove: modelData.canMove
  16.  
  17. z: {
  18. if (cards.ready)
  19. ((parentCard) ? cards.itemAt(parentCard.id).z + 1 : modelData.depth) + 100 * dragged
  20. else
  21. modelData.depth
  22. }
  23.  
  24. anchors.top: (dragged || !cards.ready) ? undefined : ((parentCard) ? cards.itemAt(parentCard.id).top : stacks[parentStack.id].top) // stacks are components defined just above
  25. anchors.left: (dragged || !cards.ready) ? undefined : ((parentCard) ? cards.itemAt(parentCard.id).left : stacks[parentStack.id].left)
  26.  
  27. anchors.topMargin: {
  28. if (!parentCard)
  29. 0
  30. else if (stacks[parentStack.id].type === CCardStack.FANNED_DOWN)
  31. parentCard.isVisible * 23 + !parentCard.isVisible * 10
  32. else if (stacks[parentStack.id].type === CCardStack.FANNED_UP)
  33. parentCard.isVisible * -23 + !parentCard.isVisible * -10
  34. else
  35. 0
  36. }
  37. anchors.leftMargin: {
  38. if (!parentCard)
  39. 0
  40. else if (stacks[parentStack.id].type === CCardStack.FANNED_RIGHT)
  41. parentCard.isVisible * 23 + !parentCard.isVisible * 10
  42. else if (stacks[parentStack.id].type === CCardStack.FANNED_LEFT)
  43. parentCard.isVisible * -23 + !parentCard.isVisible * -10
  44. else
  45. 0
  46. }
  47. }
  48.  
  49. onItemAdded: if (index + 1 == count) ready = true // I find this a little dirty, but it seems that Component.onCompleted is fired BEFORE the repeater has instanciated all its Card's
  50. }
To copy to clipboard, switch view to plain text mode 

Sadly, the behavior is somehow not triggered... When I begin to drag, "dragged" is set to true so anchors are modified to "undefined", the card should smoothly detach from its parent and join the cursor position. And more importantly, when I drop a card on another one, I it should attach itself to its new stack smoothly too. But none of these are happening for now, and I don't know why :/ I even tried in using transitions and states, and not behavior, but I had no luck neither (moreover, latency was WAY more present with this approach, so this is not a solution, would it have worked). Notice that the margins and anchors are correctly handled (ie. the cards have always their anchors correctly updated).

Would you have some ideas on how I could make these animations possible ? Or maybe did I do something wrong ?
Thank you very much in advance!