diff --git a/src/activities/railroad/ActivityInfo.qml b/src/activities/railroad/ActivityInfo.qml --- a/src/activities/railroad/ActivityInfo.qml +++ b/src/activities/railroad/ActivityInfo.qml @@ -1,6 +1,6 @@ /* GCompris - ActivityInfo.qml * - * Copyright (C) 2016 Utkarsh Tiwari + * Copyright (C) 2017 Utkarsh Tiwari * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/activities/railroad/Countdown.qml b/src/activities/railroad/Countdown.qml new file mode 100644 --- /dev/null +++ b/src/activities/railroad/Countdown.qml @@ -0,0 +1,73 @@ +/* GCompris - Countdown.qml + * + * Copyright (C) 2017 Utkarsh Tiwari + * + * Authors: + * Pascal Georges (GTK+ version) + * Utkarsh Tiwari (Qt Quick port) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +import QtQuick 2.0 +import GCompris 1.0 +import "../../core" + +Item { + id: countDown + signal triggert + property int defaultSeconds: 5 + property int seconds: defaultSeconds + opacity: 1.0 + width: childrenRect.width + height: childrenRect.height + + GCText { + id: time + visible: true + text: "Time left :" + parent.seconds + fontSize: smallSize + font.weight: Font.Bold + color: "red" + anchors.fill: parent + } + + Timer { + id: innerTimer + repeat: true + interval: 1000 + onTriggered: { + countDown.seconds--; + if (countDown.seconds == 0) { + countDown.opacity = 0 + running = false; + countDown.triggert() + } + } + } + + Behavior on opacity { + PropertyAnimation { duration: 200 } + } + + function start() { + seconds = defaultSeconds + opacity = 1; + innerTimer.start(); + } + + function stop() { + opacity = 0; + innerTimer.stop(); + } +} diff --git a/src/activities/railroad/Loco.qml b/src/activities/railroad/Loco.qml new file mode 100644 --- /dev/null +++ b/src/activities/railroad/Loco.qml @@ -0,0 +1,43 @@ +/* GCompris - Loco.qml + * + * Copyright (C) 2017 Utkarsh Tiwari + * + * Authors: + * Pascal Georges (GTK+ version) + * Utkarsh Tiwari (Qt Quick port) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +import QtQuick 2.0 +import "railroad.js" as Activity + +Item { + id:draggedItem + property int imageIndex + Image { + id: img + source: Activity.resourceURL + "loco"+ imageIndex +".svg" + height: background.height / 8.0 + width: ((background.width > background.height) ? background.width : background.height) / 5.66 + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + + } + function destroy() { + // Destroy this copy object on drop + draggedItem.destroy(); + } +} + + diff --git a/src/activities/railroad/Railroad.qml b/src/activities/railroad/Railroad.qml --- a/src/activities/railroad/Railroad.qml +++ b/src/activities/railroad/Railroad.qml @@ -20,6 +20,7 @@ * along with this program; if not, see . */ import QtQuick 2.1 +import QtQuick.Controls 2.0 import GCompris 1.0 import "../../core" import "railroad.js" as Activity @@ -55,11 +56,12 @@ property alias bar: bar property alias bonus: bonus property alias score: score + property alias timer: timer property alias sampleList: sampleList property alias listModel: listModel property alias displayList: displayList property alias animateFlow: animateFlow - property alias displayFlow: displayFlow + property alias displayRow: displayRow property alias railCollection: railCollection property alias introMessage: introMessage } @@ -69,35 +71,110 @@ } onStop: { Activity.stop() } + // Swipe message + GCText { + id: swipe + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + text: "<<== Swipe here ==>>" + fontSize: smallSize + font.weight: Font.DemiBold + color: "black" + } + + // Countdown timer + Countdown { + id: timer + anchors { + left: background.left + top: background.top + } + onTriggert: items.animateFlow.start(); + } + + // Intro message + IntroMessage { + id: introMessage + y: (background.height / 4.7) + anchors { + right: parent.right + rightMargin: 5 + left: parent.left + leftMargin: 5 + } + z: 100 + onIntroDone: { + timer.start() + } + intro: [ + qsTr("Swap left-right to view all the carriages outside display area. Memorize them before the timer ends!") + ] + } + // Top Display Area Rectangle { + width: background.width + height: background.height / 5 + color: 'transparent' + x: 2 + y : 0 + z: 1 + Flickable { id: flickTop - width: background.width - height: background.height - contentWidth: displayFlow.width - contentHeight: width + width: parent.width + height: parent.height + contentWidth: displayRow.width + contentHeight: displayRow.height flickableDirection: Flickable.HorizontalFlick - x: 2 - y : background.height / 12.5 + anchors.fill: parent + Row { - id: displayFlow - x: flickTop.x - y: 0 + id: displayRow + x: parent.x + y: background.height / 12.7 width: childrenRect.width + height: childrenRect.height spacing: background.width * 0.0025 - rotation: 0 Repeater { id: displayList model: listModel - Image { + delegate : Image { id: wagon source: Activity.resourceURL + "loco1.svg" height: background.height / 8.0 - width: ((background.width > background.height) ? background.width : background.height) / 4.66 + width: ((background.width > background.height) ? background.width : background.height) / 5.66 visible: true - rotation: displayFlow.rotation + + function checkDrop(dragItem) { + // Checks the drop location of this wagon + var globalCoordinates = dragItem.mapToItem(background, 0, 0) + if(globalCoordinates.y <= ((background.height / 12.5) + (background.height / 8))) { + var dropIndex = Activity.getDropIndex(globalCoordinates.x) + + if (dropIndex > (listModel.count - 1)) { + // Handles index overflow + dropIndex = listModel.count - 1 + } + listModel.move(listModel.count - 1, dropIndex, 1) + opacity = 1 + } + if (globalCoordinates.y > ((background.height / 12.5) + (background.height / 8))){ + // Remove it if dropped in the lower section + listModel.remove(listModel.count - 1) + } + } + + function createNewItem() { + var component = Qt.createComponent("Loco.qml"); + if (component.status === Component.Ready) { + var newItem = component.createObject(parent, {"x":x, "y":y, "z": 10 ,"imageIndex": listModel.get(index).id}); + } + return newItem + } MouseArea { id: displayWagonMouseArea @@ -105,16 +182,31 @@ enabled: introMessage.visible ? false : true anchors.fill: parent - onClicked: { + onPressed: { + if (Activity.memoryMode == true) { + drag.target = parent.createNewItem(); + parent.opacity = 0 + listModel.move(index, listModel.count - 1, 1) + } + } + onReleased: { if (Activity.memoryMode == true) { - listModel.remove(index); - Activity.isAnswer(); - } else { + var dragItem = drag.target + parent.checkDrop(dragItem) + + dragItem.destroy(); + parent.Drag.cancel() + Activity.isAnswer() + } + } + + onClicked: { + if (Activity.memoryMode == false) { + timer.stop() animateFlow.stop(); - displayFlow.x = 2; + displayRow.x = 2; listModel.clear(); Activity.memoryMode = true; - Activity.items.displayFlow.rotation = 180; Activity.items.railCollection.visible = true } } @@ -130,29 +222,30 @@ } } onXChanged: { - if (displayFlow.x >= background.width) { + if (displayRow.x >= background.width) { + timer.stop() animateFlow.stop(); - displayFlow.x = 2; + displayRow.x = 2; listModel.clear(); Activity.memoryMode = true; - displayFlow.rotation = 180; items.railCollection.visible = true; } } PropertyAnimation { id: animateFlow - target: displayFlow + target: displayRow properties: "x" from: 2 to: background.width - duration: 14000 + duration: 4000 easing.type: Easing.InExpo loops: 1 } } - ListModel { - id: listModel - } + } + + ListModel { + id: listModel } } @@ -184,23 +277,60 @@ Repeater { id: eachRow model: Activity.noOfCarriages[parent.rowNo] + Image { id: loco readonly property int uniqueID: Activity.sum(parent.rowNo) + index + property real originX + property real originY source: Activity.resourceURL + "loco" + (uniqueID + 1) + ".svg" height: background.height / 7.5 - width: ((background.width > background.height) ? background.width : background.height) / 4.66 + width: ((background.width > background.height) ? background.width : background.height) / 5.66 visible: true + + function initDrag() { + originX = x + originY = y + } + + function replace() { + x = originX + y = originY + } + + function checkDrop() { + // Checks the drop location of this wagon + var globalCoordinates = loco.mapToItem(background, 0, 0) + if(globalCoordinates.y <= ((background.height / 8.0) + (background.height / 12.5))) { + if(listModel.count == 0) { + Activity.addWagon(uniqueID + 1, 0); + } else { + var dropIndex = Activity.getDropIndex(globalCoordinates.x) + Activity.addWagon(uniqueID + 1, dropIndex); + } + } + Activity.isAnswer() + } + MouseArea { id: mouseArea hoverEnabled: true - enabled: true anchors.fill: parent - onClicked: { - Activity.addWagon(parent.uniqueID + 1); - Activity.isAnswer(); + drag.target: parent + drag.axis: (parent.y >= 0 && parent.y <= background.height / 7.5) ? Drag.YAxis : Drag.XAndYAxis + enabled: true + onPressed: { + parent.initDrag() + } + onReleased: { + parent.Drag.cancel() + parent.checkDrop() + parent.replace() } } + + Component.onCompleted: initDrag(); + states: State { name: "carHover" when: mouseArea.containsMouse @@ -231,24 +361,6 @@ } } - IntroMessage { - id: introMessage - y: (background.height / 4.7) - anchors { - right: parent.right - rightMargin: 5 - left: parent.left - leftMargin: 5 - } - z: 100 - onIntroDone: { - items.animateFlow.start(); - } - intro: [ - qsTr("Swap left-right to view all the carriages outside display area!") - ] - } - DialogHelp { id: dialogHelp onClose: home() diff --git a/src/activities/railroad/railroad.js b/src/activities/railroad/railroad.js --- a/src/activities/railroad/railroad.js +++ b/src/activities/railroad/railroad.js @@ -48,8 +48,8 @@ function initLevel() { var index = 0; memoryMode = false; - items.displayFlow.rotation = 0; items.railCollection.visible = false; + items.timer.stop(); items.animateFlow.stop(); // Stops any previous animations items.listModel.clear(); items.displayList.model = items.listModel; @@ -83,7 +83,7 @@ isReset = false; } if (items.introMessage.visible === false) { - items.animateFlow.start() + items.timer.start() } items.bar.level = currentLevel + 1; } @@ -124,8 +124,8 @@ /* Checks if the top level setup equals the solutions */ if (items.listModel.count === solutionArray.length) { var flag = true; - for (var index = items.listModel.count - 1; index > 0; index--) { - if (items.listModel.get(index).id != solutionArray[items.listModel.count - 1 - index]) { + for (var index = 0; index < items.listModel.count; index++) { + if (items.listModel.get(index).id != solutionArray[index]) { flag = false; break; } @@ -144,8 +144,23 @@ return total; } -function addWagon(index) { +function addWagon(index, dropIndex) { /* Appends wagons to the display area */ - items.listModel.append({"id" : index}); - (items.displayList.itemAt(items.listModel.count - 1)).source = resourceURL + "loco" + (index) + ".svg"; + items.listModel.insert(dropIndex, {"id" : index}); + (items.displayList.itemAt(dropIndex)).source = resourceURL + "loco" + (index) + ".svg"; +} + +function getDropIndex(x) { + var count = items.listModel.count; + for (var index = 0; index < count; index++) { + var xVal = items.displayList.itemAt(index).x; + var itemWidth = items.displayList.itemAt(index).width; + if (x < xVal && index == 0) { + return 0; + } else if ((xVal + itemWidth + items.displayRow.spacing) <= x && index == (count - 1)) { + return count; + } else if (xVal <= x && x < (xVal + itemWidth + items.displayRow.spacing)) { + return index + 1; + } + } }