diff --git a/src/activities/crane/ActivityInfo.qml b/src/activities/crane/ActivityInfo.qml index 4315415a3..161764948 100755 --- a/src/activities/crane/ActivityInfo.qml +++ b/src/activities/crane/ActivityInfo.qml @@ -1,40 +1,40 @@ /* GCompris - ActivityInfo.qml * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (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 GCompris 1.0 ActivityInfo { name: "crane/Crane.qml" - difficulty: 1 + difficulty: 2 icon: "crane/crane.svg" author: "Stefan Toncu <stefan.toncu29@gmail.com>" demo: true - title: "Build the same model" - description: "Drive the crane and copy the model" + title: qsTr("Build the same model") + description: qsTr("Drive the crane and copy the model") //intro: "put here in comment the text for the intro voice" - goal: "Motor-coordination" - prerequisite: "Mouse/keyboard manipulation" - manual: "Move the items in the left frame to copy their position in the right model. Next to the crane itself, you will find four arrows that let you move the items. To select the item to move, just click on it. If you prefer, you can use the arrow keys and the space or tab key instead. On a mobile version, you can also swipe up/down/left/right to move the items in the left frame." + goal: qsTr("Motor-coordination") + prerequisite: qsTr("Mouse/keyboard manipulation") + manual: qsTr("Move the items in the left frame to copy their position in the right model. Next to the crane itself, you will find four arrows that let you move the items. To select the item to move, just click on it. If you prefer, you can use the arrow keys and the space or tab key instead. On a mobile version, you can also swipe up/down/left/right to move the items in the left frame.") credit: "" section: "puzzle" - createdInVersion: 6000 + createdInVersion: 7000 } diff --git a/src/activities/crane/Crane.qml b/src/activities/crane/Crane.qml index d7c44fa1f..485da14cf 100755 --- a/src/activities/crane/Crane.qml +++ b/src/activities/crane/Crane.qml @@ -1,355 +1,385 @@ /* GCompris - Crane.qml * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (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.1 import GCompris 1.0 import "../../core" import "crane.js" as Activity /* TODOs 1. add grid for first levels 2. change images from png to svg */ ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent - // source: "resource/crane-bg.svgz" - color: "#F5F1DE" + color: "white" signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property alias bar: bar property alias bonus: bonus property alias board: board property alias grid: grid property alias repeater: repeater property alias modelRepeater: modelRepeater property var names property var names2 property int selected property int columns property int rows + property bool ok: true property int sensivity: 80 property int barHeightAddon: ApplicationSettings.isBarHidden ? 1 : 3 property int cellSize: Math.min(background.width / 11 , background.height / (9 + barHeightAddon)) + property bool gameFinished: false } onStart: { Activity.start(items) } onStop: { Activity.stop() } property bool portrait: height > width ? true : false Keys.onPressed: { if (event.key === Qt.Key_Left) Activity.move("left") else if (event.key === Qt.Key_Right) Activity.move("right") else if (event.key === Qt.Key_Up) Activity.move("up") else if (event.key === Qt.Key_Down) Activity.move("down") else if (event.key === Qt.Key_Space || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Return) Activity.move("next") } //implementation of Swipe effect MouseArea { anchors.fill: parent property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) } Rectangle { id: board color: "lightblue" radius: width * 0.02 z: 1 anchors { verticalCenter: crane_vertical.verticalCenter right: crane_vertical.left margins: 15 } width: background.portrait ? parent.width * 0.65 : ((parent.width - anchors.margins * 3 - crane_vertical.width) / 2 ) * 0.9 height: background.portrait ? (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height ) / 2 : (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height) * 0.9 } Grid { id: grid columns: items.columns rows: items.rows z: 3 anchors.fill: board Repeater { id: repeater Image { id: figure width: board.width/items.columns height: board.height/items.rows property bool showSelected: false property alias selected: selected + property alias anim: anim + property int distance + property int indexChange + property int startPoint + property string animationProperty property int _index: index // make current index accessible from outside + SequentialAnimation { + id: anim + PropertyAction { target: items; property: "ok"; value: "false"} + NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint; to: figure.startPoint + distance; duration: 400 } + PropertyAction { target: figure; property: "opacity"; value: 0 } + NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint + distance; to: figure.startPoint; duration: 0; } + PropertyAction { target: figure; property: "opacity"; value: 1 } + PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "source"; value: figure.source } + PropertyAction { target: figure; property: "source"; value: "" } + PropertyAction { target: items; property: "ok"; value: "true"} + ScriptAction { script: Activity.checkAnswer() } + } + MouseArea { anchors.fill: parent // Swipe effect property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) // Select a figure onClicked: source != "" ? items.selected = index : undefined } // selected marker Image { id: selected source: "resource/selected.png" width: parent.width height: parent.height // show only on the selected figure opacity: parent._index == items.selected ? 1 : 0 + + Behavior on opacity { + NumberAnimation { duration: 400 } + } } } } } Rectangle { id: modelBoard color: "pink" radius: width * 0.02 anchors { left: background.portrait ? board.left : crane_vertical.right top: background.portrait ? crane_body.bottom : parent.top topMargin: background.portrait ? board.anchors.margins : crane_top.height * 1.5 margins: board.anchors.margins } width: board.width height: board.height Grid { id: modelGrid columns: items.columns rows: items.rows Repeater { id: modelRepeater Image { id: modelFigure width: board.width/items.columns height: board.height/items.rows } } } } Image { id: crane_top - source: "resource/crane_up.svgz" + source: "resource/crane_up.svg" sourceSize.width: background.portrait ? background.width * 0.8 : background.width * 0.5 sourceSize.height: background.portrait ? background.height * 0.03 : background.height * 0.06 width: background.portrait ? background.width * 0.8 : background.width * 0.5 height: background.portrait ? background.height * 0.03 : background.height * 0.06 z: 3 anchors { top: parent.top right: crane_vertical.right rightMargin: 0 margins: board.anchors.margins } } Image { id: crane_vertical - source: "resource/crane_vertical.svgz" + source: "resource/crane_vertical.svg" sourceSize.width: background.width * 0.04 sourceSize.height: background.height * 0.73 width: background.width * 0.05 height: background.portrait ? background.height * 0.45 : background.height * 0.73 anchors { top: crane_top.top right: background.portrait ? parent.right : parent.horizontalCenter rightMargin: background.portrait ? width / 2 : - width / 2 topMargin: board.anchors.margins } } Image { id: crane_body - source: "resource/crane_only2.svgz" + source: "resource/crane_only.svg" sourceSize.width: parent.width / 6 sourceSize.height: parent.height/ 4 anchors { top: crane_vertical.bottom topMargin: - (height / 1.8) right: crane_vertical.right margins: board.anchors.margins } } Image { id: crane_wire - source: "resource/crane-wire.svgz" + source: "resource/crane-wire.svg" sourceSize.width: parent.width / 22 sourceSize.height: parent.width / 17 anchors { right: crane_body.left bottom: crane_command.verticalCenter } } Image { id: crane_command - source: "resource/command.svgz" + source: "resource/command.svg" sourceSize.width: parent.width / 4 sourceSize.height: parent.height/ 3.5 mirror: true anchors { top: crane_body.top bottom: crane_body.bottom right: crane_wire.left rightMargin: 0 margins: board.anchors.margins } Controls { id: up - source: "resource/arrow_up.svgz" + source: "resource/arrow_up.svg" anchors { left: parent.left leftMargin: parent.width / 10 } command: "up" } Controls { id: down - source: "resource/arrow_down.svgz" + source: "resource/arrow_down.svg" anchors { left: up.right leftMargin: parent.width / 20 } command: "down" } Controls { id: left - source: "resource/arrow_left.svgz" + source: "resource/arrow_left.svg" anchors { right: right.left rightMargin: parent.width / 20 } command: "left" } Controls { id: right - source: "resource/arrow_right.svgz" + source: "resource/arrow_right.svg" anchors { right: parent.right rightMargin: parent.width / 10 } command: "right" } } Rectangle { id: cable color: "black" width: 5 height: convert.y x: convert.x + items.repeater.itemAt(items.selected).width / 2 y: crane_top.height/2 z: 1 property var convert: items.repeater.mapToItem(background,items.repeater.itemAt(items.selected).x,items.repeater.itemAt(items.selected).y) + + Behavior on x { + NumberAnimation { duration: 400 } + } + Behavior on height { + NumberAnimation { duration: 400 } + } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/crane/crane.js b/src/activities/crane/crane.js index 09ab3470e..9c62ec63d 100755 --- a/src/activities/crane/crane.js +++ b/src/activities/crane/crane.js @@ -1,250 +1,249 @@ /* GCompris - crane.js * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (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 . */ .pragma library .import QtQuick 2.0 as Quick +.import "qrc:/gcompris/src/core/core.js" as Core + var currentLevel = 0 var numberOfLevel = 6 var items var url = "qrc:/gcompris/src/activities/crane/resource/" var howManyFigures = [4,5,6,7,7,7] var allNames = ["resource/bulb.png","resource/letter-a.png","resource/letter-b.png", "resource/rectangle1.png","resource/rectangle2.png","resource/square1.png", "resource/square2.png","resource/triangle1.png","resource/triangle2.png", "resource/tux.png","resource/water_drop1.png","resource/water_drop2.png", "resource/water_spot1.png","resource/water_spot2.png"] function start(items_) { items = items_ currentLevel = 0 initLevel() } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 init() } function init() { items.columns = 7 items.rows = 6 + items.gameFinished = false setRandomModel() items.selected = getNextIndex1(0) } -function shuffle(input) { - for (var i = input.length-1; i >= 0; i--) { - - var randomIndex = Math.floor(Math.random()*(i+1)); - var itemAtIndex = input[randomIndex]; - - input[randomIndex] = input[i]; - input[i] = itemAtIndex; - } -} - var names = [] var names2 = [] - function setRandomModel(){ // randomize the names - shuffle(allNames) + Core.shuffle(allNames) var numbers = [] for (var i = 0; i < items.columns * items.rows; i++){ names[i] = "" // reset the board names2[i] = "" numbers[i] = i; // generate columns*rows numbers } //get "howManyFigures[currentLevel]" random numbers - shuffle(numbers) + Core.shuffle(numbers) for (i = 0; i < howManyFigures[currentLevel]; i++) names[numbers[i]] = allNames[i] - shuffle(numbers) + Core.shuffle(numbers) for (i = 0; i < howManyFigures[currentLevel]; i++) names2[numbers[i]] = allNames[i] //DEBUGGING // print("names: ",names) // print("names2: ",names2) items.repeater.model = names.length items.modelRepeater.model = names2.length for (i = 0; i < names.length; i++) { items.repeater.itemAt(i).source = names[i] items.modelRepeater.itemAt(i).source = names2[i] } } function getNextIndex1(index) { var length = items.repeater.count for(var i = index-1; i >= 0; i--) { if (items.repeater.itemAt(i).source != ""){ return i } } for(i = length-1; i > index; i--) { if (items.repeater.itemAt(i).source != ""){ return i } } return -1; } -//names function getNextIndex(source) { var length = names.length //find index of curent image in ordonated "names" list for(var i = 0; i < length; i++) { var name = "qrc:/gcompris/src/activities/crane/" + names[i] -// print("name: ",name) if (name == source) { break } } //go to next index i++ //bool variable var ok = false //search from current index for (; i 40 || Math.abs(deltay) > 40) { if (deltax > 30 && Math.abs(deltay) < items.sensivity) { move("right") } else if (deltax < -30 && Math.abs(deltay) < items.sensivity) { move("left") } else if (Math.abs(deltax) < items.sensivity && deltay > 30) { move("down") } else if (Math.abs(deltax) < items.sensivity && deltay < 30) { move("up") } } } + function move(move) { - if (move === "left") { - if (items.selected % items.columns != 0) - makeMove(-1) - } else if (move === "right") { - if ((items.selected+1) % items.columns != 0) - makeMove(1) - } else if (move === "up") { - if (items.selected > items.columns-1) - makeMove(-items.columns) - } else if (move === "down") { - if (items.selected < (items.repeater.count-items.columns)) - makeMove(items.columns) - } else if (move === "next") { - items.selected = getNextIndex(items.repeater.itemAt(items.selected).source) - } + if (items.ok == true && items.gameFinished == false) { + var item = items.repeater.itemAt(items.selected) + if (move === "left") { + if (items.selected % items.columns != 0) + makeMove(item,-item.width,item.x,-1,"x") + } else if (move === "right") { + if ((items.selected+1) % items.columns != 0) + makeMove(item,item.width,item.x,1,"x") + } else if (move === "up") { + if (items.selected > items.columns-1) + makeMove(item,-item.height,item.y,-items.columns,"y") + } else if (move === "down") { + if (items.selected < (items.repeater.count-items.columns)) + makeMove(item,item.height,item.y,items.columns,"y") + } else if (move === "next") { + items.selected = getNextIndex(items.repeater.itemAt(items.selected).source) + } + } } -function makeMove(add) { +function makeMove(item,distance,startPoint,add,animationProperty) { if (items.repeater.itemAt(items.selected+add).source == "") { - items.repeater.itemAt(items.selected+add).source = items.repeater.itemAt(items.selected).source - items.repeater.itemAt(items.selected).source = "" + //setup the animation + item.distance = distance + item.indexChange = add + item.startPoint = startPoint + item.animationProperty = animationProperty + //start the animation + item.anim.start() + //update the selected item items.selected += add; - checkAnswer() } } function checkAnswer() { var count = 0 for (var i = 0; i < items.repeater.count; i++) { if (items.repeater.itemAt(i).source != items.modelRepeater.itemAt(i).source){ count = -1 } } if (count == 0) { items.bonus.good("flower") + items.gameFinished = true } } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } diff --git a/tools/menus/crane.qml b/tools/menus/crane.qml deleted file mode 100644 index 070527643..000000000 --- a/tools/menus/crane.qml +++ /dev/null @@ -1,33 +0,0 @@ -/* GCompris - ActivityInfo.qml - * - * Copyright (C) 2015 Your Name - * - * 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 GCompris 1.0 - -ActivityInfo { - name: "crane/Crane.qml" - difficulty: 2 - icon: "crane/crane.svg" - author: "Marc BRUN" - demo: true - title: qsTr("Build the same model") - description: qsTr("Drive the crane and copy the model") - goal: qsTr("Motor-coordination") - prerequisite: qsTr("Mouse manipulation") - manual: qsTr("Move the items in the bottom left frame to copy their position in the top right model. Below the crane itself, you will find four arrows that let you move items. To select the item to move, just click on it. If you prefer, you can use the arrow keys and the space or tab key instead.") - credit: "" - section: "/puzzle" -} diff --git a/tools/menus/resource/crane.svg b/tools/menus/resource/crane.svg deleted file mode 100644 index 0040e553e..000000000 --- a/tools/menus/resource/crane.svg +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -