Warning, /education/gcompris/src/activities/baby_mouse/Baby_mouse.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - Baby_mouse.qml
0002  *
0003  * SPDX-FileCopyrightText: 2021 Mariam Fahmy <mariamfahmy66@gmail.com>
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 import QtQuick 2.12
0007 import GCompris 1.0
0008 
0009 import "../../core"
0010 import "baby_mouse.js" as Activity
0011 import "qrc:/gcompris/src/core/core.js" as Core
0012 
0013 ActivityBase {
0014     id: activity
0015 
0016     onStart: focus = true
0017     onStop: {}
0018 
0019     pageComponent: Image {
0020         id: background
0021         source: "qrc:/gcompris/src/activities/colors/resource/background.svg"
0022         sourceSize.width: width
0023         sourceSize.height: height
0024         fillMode: Image.PreserveAspectCrop
0025 
0026         signal start
0027         signal stop
0028 
0029         readonly property real defaultScale: 1
0030         readonly property real mediumScale: 1.2
0031         readonly property real largeScale: 1.4
0032 
0033         readonly property int toleranceLimit: 5
0034 
0035         property bool isArrowPressed: false
0036 
0037         Component.onCompleted: {
0038             activity.start.connect(start)
0039             activity.stop.connect(stop)
0040         }
0041 
0042         // Add here the QML items you need to access in javascript
0043         QtObject {
0044             id: items
0045             property Item main: activity.main
0046             property GCSfx audioEffects: activity.audioEffects
0047             property alias duckModel: duckModel
0048             property bool hasBeenDragged: false
0049         }
0050 
0051         onStart: {
0052             Activity.start(items)
0053             resetDuckPosition()
0054         }
0055         onStop: {
0056             Activity.stop()
0057             resetArrowTimer.stop()
0058             pressArrowTimer.stop()
0059         }
0060 
0061         Item {
0062             id: mainArea
0063             width: background.width - duckGrid.width
0064             height: background.height - bar.height * 1.05 - y
0065             anchors.left: duckGrid.right
0066             anchors.top: arrowsArea.bottom
0067 
0068             // To detect click in this area with mainAreaBlock...
0069             Rectangle {
0070                 anchors.fill: parent
0071                 color: "transparent"
0072             }
0073 
0074             readonly property double rightDirectionLimit: mainArea.width - mainDuck.width
0075             readonly property double downDirectionLimit: mainArea.height - mainDuck.height
0076 
0077             property alias mainDuckX: mainDuck.x
0078             property alias mainDuckY: mainDuck.y
0079             property real previousDuckX
0080             property real previousDuckY
0081 
0082             Image {
0083                 id: mainDuck
0084                 source: Activity.duckColorURL + "blue_duck.svg"
0085                 sourceSize.width: 70 * ApplicationInfo.ratio
0086                 sourceSize.height: 70 * ApplicationInfo.ratio
0087 
0088                 SequentialAnimation {
0089                     running: true
0090                     loops: Animation.Infinite
0091                     NumberAnimation {
0092                         target: mainDuck
0093                         property: "rotation"
0094                         from: -10; to: 10
0095                         duration: 400 + Math.floor(Math.random() * 400)
0096                         easing.type: Easing.InOutQuad
0097                     }
0098                     NumberAnimation {
0099                         target: mainDuck
0100                         property: "rotation"
0101                         from: 10; to: -10
0102                         duration: 400 + Math.floor(Math.random() * 400)
0103                         easing.type: Easing.InOutQuad
0104                     }
0105                 }
0106             }
0107 
0108             MouseArea {
0109                 id: mouseMovement
0110                 anchors.fill: parent
0111                 hoverEnabled: true
0112 
0113                 property real startX: 0
0114                 property real startY: 0
0115 
0116                 onEntered: {
0117                     setStartPosition()
0118                 }
0119 
0120                 onPositionChanged: {
0121                     if(items.hasBeenDragged) {
0122                         setStartPosition()
0123                         items.hasBeenDragged = false
0124                         return;
0125                     }
0126 
0127                     resetArrowTimer.restart()
0128 
0129                     // Comparing the current mouse position with the previous mouse position
0130                     var moveX = mouseX - startX
0131                     var moveY = mouseY - startY
0132 
0133                     background.moveDuckHorizontally(moveX)
0134                     background.moveDuckVertically(moveY)
0135                     background.indicateArrowScale()
0136 
0137                     setStartPosition()
0138                 }
0139 
0140                 function setStartPosition() {
0141                     startX = mouseX
0142                     startY = mouseY
0143                 }
0144             }
0145         }
0146 
0147         MultiPointTouchArea {
0148             id: touchArea
0149             anchors.fill: parent
0150 
0151             property real previousX
0152             property real previousY
0153 
0154             property real startX
0155             property real startY
0156 
0157             onPressed: {
0158                 for(var i in touchPoints) {
0159                     var touch = touchPoints[i]
0160                     previousX = touch.x
0161                     previousY = touch.y
0162 
0163                     startX = touch.x
0164                     startY = touch.y
0165 
0166                     items.hasBeenDragged = true
0167 
0168                     var arrowsPoint = parent.mapToItem(arrowsArea, touch.x, touch.y)
0169                     var arrowsBlock = arrowsArea.childAt(arrowsPoint.x, arrowsPoint.y)
0170 
0171                     if(arrowsBlock) {
0172                         background.isArrowPressed = true
0173                         if(arrowsArea.contains(arrowsPoint.x, arrowsPoint.y, arrowsArea.upArrow)) {
0174                             pressArrowTimer.upPressed = true
0175                             pressArrowTimer.start()
0176                         }
0177                         else if(arrowsArea.contains(arrowsPoint.x, arrowsPoint.y, arrowsArea.downArrow)) {
0178                             pressArrowTimer.downPressed = true
0179                             pressArrowTimer.start()
0180                         }
0181                         else if(arrowsArea.contains(arrowsPoint.x, arrowsPoint.y, arrowsArea.leftArrow)) {
0182                             pressArrowTimer.start()
0183                         }
0184                         else if(arrowsArea.contains(arrowsPoint.x, arrowsPoint.y, arrowsArea.rightArrow)) {
0185                             pressArrowTimer.rightPressed = true
0186                             pressArrowTimer.start()
0187                         }
0188                     }
0189                 }
0190             }
0191 
0192             onTouchUpdated: {
0193                 if(background.isArrowPressed) return;
0194                 for(var i in touchPoints) {
0195                     var touch = touchPoints[i]
0196                     var moveX = touch.x - previousX
0197                     var moveY = touch.y - previousY
0198 
0199                     background.moveDuckHorizontally(moveX)
0200                     background.moveDuckVertically(moveY)
0201                     background.indicateArrowScale()
0202 
0203                     previousX = touch.x
0204                     previousY = touch.y
0205                 }
0206             }
0207 
0208             onReleased: {
0209                 for(var i in touchPoints) {
0210                     var touch = touchPoints[i]
0211 
0212                     var maxToleranceX = startX + background.toleranceLimit
0213                     var minToleranceX = startX - background.toleranceLimit
0214 
0215                     var maxToleranceY = startY + background.toleranceLimit
0216                     var minToleranceY = startY - background.toleranceLimit
0217 
0218                     if(minToleranceX <= touch.x && touch.x <= maxToleranceX && minToleranceY <= touch.y && touch.y <= maxToleranceY) {
0219                         var ducksPoint = parent.mapToItem(duckGrid, touch.x, touch.y)
0220                         var ducksBlock = duckGrid.itemAt(ducksPoint.x, ducksPoint.y)
0221 
0222                         var mainAreaPoint = parent.mapToItem(mainArea, touch.x, touch.y)
0223                         var mainAreaBlock = mainArea.childAt(mainAreaPoint.x, mainAreaPoint.y)
0224 
0225                         if(ducksBlock) {
0226                             ducksBlock.restartAnimation()
0227                         }
0228                         else if(mainAreaBlock){
0229                             pressCircle.x = touch.x - pressCircle.width / 2
0230                             pressCircle.y = touch.y - pressCircle.height / 2
0231                             pressCircle.visible = true
0232                             Activity.playSound(4)
0233                         }
0234                     }
0235 
0236                     background.isArrowPressed = false
0237                     background.resetArrowScale()
0238                     pressArrowTimer.stopTimer()
0239                 }
0240             }
0241         }
0242 
0243         Timer {
0244             id: resetArrowTimer
0245             interval: 200
0246             onTriggered: background.resetArrowScale()
0247         }
0248 
0249         Timer {
0250             id: pressArrowTimer
0251 
0252             property bool upPressed: false
0253             property bool downPressed: false
0254             property bool rightPressed: false
0255 
0256             function stopTimer() {
0257                 upPressed = false
0258                 downPressed = false
0259                 rightPressed = false
0260                 stop()
0261             }
0262 
0263             interval: 10
0264             repeat: true
0265             triggeredOnStart: true
0266             onTriggered: upPressed ? arrowsArea.upArrow.moveDuckUp() :
0267                                      downPressed ? arrowsArea.downArrow.moveDuckDown() :
0268                                                    rightPressed ? arrowsArea.rightArrow.moveDuckToRight() :
0269                                                                   arrowsArea.leftArrow.moveDuckToLeft()
0270         }
0271 
0272         function moveDuckHorizontally(moveX) {
0273             mainArea.previousDuckX = mainArea.mainDuckX
0274 
0275             // Duck Motion in x-direction.
0276             if(mainArea.previousDuckX + moveX >= mainArea.rightDirectionLimit) {
0277                 mainArea.mainDuckX = mainArea.rightDirectionLimit
0278             }
0279             else if(mainArea.previousDuckX + moveX <= 0) {
0280                 mainArea.mainDuckX = 0
0281             }
0282             else {
0283                 mainArea.mainDuckX += moveX
0284             }
0285         }
0286 
0287         function moveDuckVertically(moveY) {
0288             mainArea.previousDuckY = mainArea.mainDuckY
0289 
0290             // Duck Motion in y-direction.
0291             if(mainArea.previousDuckY + moveY >= mainArea.downDirectionLimit) {
0292                 mainArea.mainDuckY = mainArea.downDirectionLimit
0293             }
0294             else if(mainArea.previousDuckY + moveY <= 0) {
0295                 mainArea.mainDuckY = 0
0296             }
0297             else {
0298                 mainArea.mainDuckY += moveY
0299             }
0300         }
0301 
0302         function indicateArrowScale() {
0303             resetArrowScale()
0304             var diffX = mainArea.mainDuckX - mainArea.previousDuckX
0305             var diffY = mainArea.mainDuckY - mainArea.previousDuckY
0306 
0307             if(diffX === 0 && diffY === 0) return;
0308 
0309             // In case main duck moves in the y-direction only.
0310             if(diffX === 0) {
0311                 if(diffY < 0) arrowsArea.upArrow.scale = largeScale
0312                 else arrowsArea.downArrow.scale = largeScale
0313                 return
0314             }
0315 
0316             // In case main duck moves in the x-direction only.
0317             if(diffY === 0) {
0318                 if(diffX < 0) arrowsArea.leftArrow.scale = largeScale
0319                 else arrowsArea.rightArrow.scale = largeScale
0320                 return
0321             }
0322 
0323             // In case main duck moves in both x and y directions.
0324             if(Math.abs(diffX) > Math.abs(diffY)) {
0325                 if(diffX < 0) arrowsArea.leftArrow.scale = largeScale
0326                 else arrowsArea.rightArrow.scale = largeScale
0327 
0328                 if(diffY < 0) arrowsArea.upArrow.scale = mediumScale
0329                 else arrowsArea.downArrow.scale = mediumScale
0330             }
0331             else if(Math.abs(diffX) < Math.abs(diffY)) {
0332                 if(diffX < 0) arrowsArea.leftArrow.scale = mediumScale
0333                 else arrowsArea.rightArrow.scale = mediumScale
0334 
0335                 if(diffY < 0) arrowsArea.upArrow.scale = largeScale
0336                 else arrowsArea.downArrow.scale = largeScale
0337             }
0338             else {
0339                 if(diffX < 0) arrowsArea.leftArrow.scale = mediumScale
0340                 else arrowsArea.rightArrow.scale = mediumScale
0341 
0342                 if(diffY < 0) arrowsArea.upArrow.scale = mediumScale
0343                 else arrowsArea.downArrow.scale = mediumScale
0344             }
0345         }
0346 
0347         // Area for displaying the 4 arrows.
0348         Item {
0349             id: arrowsArea
0350             width: duckGrid.cellWidth
0351             height: width
0352             anchors.top: parent.top
0353             anchors.topMargin: width * 0.1
0354             anchors.right: parent.right
0355             anchors.rightMargin: anchors.topMargin
0356 
0357             property alias upArrow: upArrow
0358             property alias leftArrow: leftArrow
0359             property alias downArrow: downArrow
0360             property alias rightArrow: rightArrow
0361 
0362             function contains(x, y, item) {
0363                 return (x > item.x && x < item.x + item.width &&
0364                         y > item.y && y < item.y + item.height)
0365             }
0366 
0367             Image {
0368                 id: upArrow
0369                 source: Activity.arrowImageURL
0370                 width: 0.33 * arrowsArea.width
0371                 sourceSize.width: width * largeScale
0372                 fillMode: Image.PreserveAspectFit
0373                 anchors.top: arrowsArea.top
0374                 anchors.horizontalCenter: arrowsArea.horizontalCenter
0375                 rotation: -90
0376 
0377                 function moveDuckUp() {
0378                     upArrow.scale = background.largeScale
0379                     if(mainArea.mainDuckY - 1 >= 0) {
0380                         mainArea.mainDuckY -= 5;
0381                     }
0382                 }
0383 
0384                 Behavior on scale { NumberAnimation { duration: 200 } }
0385             }
0386 
0387             Image {
0388                 id: rightArrow
0389                 source: Activity.arrowImageURL
0390                 width: upArrow.width
0391                 sourceSize.width: upArrow.sourceSize.width
0392                 fillMode: Image.PreserveAspectFit
0393                 anchors.right: arrowsArea.right
0394                 anchors.verticalCenter: arrowsArea.verticalCenter
0395                 rotation: 0
0396 
0397                 function moveDuckToRight() {
0398                     rightArrow.scale = background.largeScale
0399                     if(mainArea.mainDuckX + 1 <= mainArea.rightDirectionLimit) {
0400                         mainArea.mainDuckX += 5;
0401                     }
0402                 }
0403 
0404                 Behavior on scale { NumberAnimation { duration: 200 } }
0405             }
0406 
0407             Image {
0408                 id: downArrow
0409                 source: Activity.arrowImageURL
0410                 width: upArrow.width
0411                 sourceSize.width: upArrow.sourceSize.width
0412                 fillMode: Image.PreserveAspectFit
0413                 anchors.bottom: arrowsArea.bottom
0414                 anchors.horizontalCenter: arrowsArea.horizontalCenter
0415                 anchors.left: upArrow.left
0416                 rotation: 90
0417 
0418                 function moveDuckDown() {
0419                     downArrow.scale = background.largeScale
0420                     if(mainArea.mainDuckY + 1 <= mainArea.downDirectionLimit) {
0421                         mainArea.mainDuckY += 5;
0422                     }
0423                 }
0424 
0425                 Behavior on scale { NumberAnimation { duration: 200 } }
0426             }
0427 
0428             Image {
0429                 id: leftArrow
0430                 source: Activity.arrowImageURL
0431                 width: upArrow.width
0432                 sourceSize.width: upArrow.sourceSize.width
0433                 fillMode: Image.PreserveAspectFit
0434                 anchors.left: arrowsArea.left
0435                 anchors.verticalCenter: arrowsArea.verticalCenter
0436                 rotation: 180
0437 
0438                 function moveDuckToLeft() {
0439                     leftArrow.scale = background.largeScale
0440                     if(mainArea.mainDuckX - 1 >= 0) {
0441                         mainArea.mainDuckX -= 5;
0442                     }
0443                 }
0444 
0445                 Behavior on scale { NumberAnimation { duration: 200 } }
0446             }
0447         }
0448 
0449         ListModel {
0450             id: duckModel
0451         }
0452 
0453         GridView {
0454             id: duckGrid
0455             model: duckModel
0456             anchors.top: parent.top
0457             anchors.bottom: bar.top
0458             anchors.left: parent.left
0459             anchors.margins: 5
0460             width: mainDuck.width
0461             flow: GridView.FlowTopToBottom
0462             interactive: false
0463             cellWidth: duckGrid.width
0464             cellHeight: mainDuck.height * 1.1
0465 
0466             delegate: Image {
0467                 id: duckImage
0468                 source: Activity.duckColorURL + model.image + ".svg"
0469                 sourceSize.width: duckGrid.cellWidth
0470                 sourceSize.height: mainDuck.height
0471 
0472                 function restartAnimation() {
0473                     duckAnim.start()
0474                 }
0475 
0476                 ParticleSystemStarLoader {
0477                     id: particles
0478                     clip: false
0479                 }
0480 
0481                 SequentialAnimation {
0482                     id: duckAnim
0483                     loops: 1
0484                     NumberAnimation {
0485                         target: duckImage
0486                         property: "rotation"
0487                         from: 0; to: 360
0488                         duration: 600
0489                         easing.type: Easing.InOutQuad
0490                     }
0491                     onRunningChanged: {
0492                         if(running) {
0493                             Activity.playSound(index)
0494                             particles.burst(20)
0495                         }
0496                         else {
0497                             rotation = 0
0498                         }
0499                     }
0500                 }
0501             }
0502 
0503             add: Transition {
0504                 PathAnimation {
0505                     path: Path {
0506                         PathCurve { x: 0; y: 0}
0507                         PathCurve {}
0508                     }
0509                     easing.type: Easing.InOutQuad
0510                     duration: 1000
0511                 }
0512             }
0513         }
0514 
0515         Rectangle {
0516             id: pressCircle
0517             width: ApplicationInfo.ratio * 20
0518             height: width
0519             color: "#E77936"
0520             border.width: width * 0.1
0521             border.color: "#EEEEEE"
0522             visible: false
0523             radius: width * 0.5
0524         }
0525 
0526         onWidthChanged: {
0527             resetDuckPosition()
0528             pressCircle.visible = false;
0529         }
0530 
0531         onHeightChanged: {
0532             resetDuckPosition()
0533             pressCircle.visible = false;
0534         }
0535 
0536         function resetDuckPosition() {
0537             mainArea.mainDuckX = mainArea.width / 2
0538             mainArea.mainDuckY = mainArea.height / 2
0539         }
0540 
0541         function resetArrowScale() {
0542             arrowsArea.upArrow.scale = defaultScale
0543             arrowsArea.downArrow.scale = defaultScale
0544             arrowsArea.leftArrow.scale = defaultScale
0545             arrowsArea.rightArrow.scale = defaultScale
0546         }
0547 
0548         DialogHelp {
0549             id: dialogHelp
0550             onClose: home()
0551         }
0552 
0553         Bar {
0554             id: bar
0555             content: BarEnumContent { value: help | home }
0556             onHelpClicked: {
0557                 displayDialog(dialogHelp)
0558             }
0559             onHomeClicked: activity.home()
0560         }
0561     }
0562 }