diff --git a/src/activities/programmingMaze/ActivityInfo.qml b/src/activities/programmingMaze/ActivityInfo.qml --- a/src/activities/programmingMaze/ActivityInfo.qml +++ b/src/activities/programmingMaze/ActivityInfo.qml @@ -1,6 +1,7 @@ /* GCompris - ActivityInfo.qml * * Copyright (C) 2015 Siddhesh Suthar + * Copyright (C) 2018 Aman Kumar Gupta * * 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 @@ -48,5 +49,5 @@ qsTr("") credit: "" section: "fun" - createdInVersion: 9000 + createdInVersion: 9500 } diff --git a/src/activities/programmingMaze/AnswerSheet.qml b/src/activities/programmingMaze/AnswerSheet.qml --- a/src/activities/programmingMaze/AnswerSheet.qml +++ b/src/activities/programmingMaze/AnswerSheet.qml @@ -1,6 +1,7 @@ /* GCompris - AnswerSheet.qml * * Copyright (C) 2015 Siddhesh Suthar + * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar @@ -25,11 +26,8 @@ import "programmingMaze.js" as Activity GridView { - id: answerSheet - property Item background - property ListModel currentModel + id: codeArea z: 1 - width: background.width * 0.4 height: background.height * 0.29 cellWidth: background.buttonWidth @@ -54,6 +52,7 @@ keyNavigationWraps: true focus: true + property ListModel currentModel property int draggedItemIndex: -1 property int possibleDropIndex: -1 property int possibleDropRemoveIndex: -1 @@ -69,15 +68,12 @@ */ property int initialEditItemIndex: -1 - //Tells if any instruction is selected for editing. + // Tells if any instruction is selected for editing. property bool isEditingInstruction: false - Keys.onRightPressed: moveCurrentIndexRight() - Keys.onLeftPressed: moveCurrentIndexLeft() - Keys.onUpPressed: moveCurrentIndexUp() - Keys.onDownPressed: moveCurrentIndexDown() - Keys.onEnterPressed: background.runCodeOrResetTux() - Keys.onReturnPressed: background.runCodeOrResetTux() + signal spaceKeyPressed + signal tabKeyPressed + signal deleteKeyPressed /** * There can be three possibilities here: @@ -86,32 +82,34 @@ * 2. We want to select an instruction to edit, or deselect it. * 3. We want to append an instruction. */ - Keys.onSpacePressed: { + onSpaceKeyPressed: { if(currentIndex != -1) { - if(instruction.instructionToInsert && (items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed)) { + if(instructionArea.instructionToInsert && (items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed)) { var isInstructionInserted = appendInstruction() if(isInstructionInserted) currentModel.move(currentModel.count - 1, currentIndex, 1) } else { if((initialEditItemIndex == currentIndex) || (initialEditItemIndex == -1 && currentIndex != -1)) { - answerSheet.isEditingInstruction = !answerSheet.isEditingInstruction + codeArea.isEditingInstruction = !codeArea.isEditingInstruction } - if(!answerSheet.isEditingInstruction) - answerSheet.initialEditItemIndex = -1 + if(!codeArea.isEditingInstruction) + codeArea.initialEditItemIndex = -1 else initialEditItemIndex = currentIndex - var calculatedX = (initialEditItemIndex % 4) * answerSheet.cellWidth - var calculatedY = Math.floor(initialEditItemIndex / 4) * answerSheet.cellHeight + + var calculatedX = (initialEditItemIndex % 4) * codeArea.cellWidth + var calculatedY = Math.floor(initialEditItemIndex / 4) * codeArea.cellHeight editInstructionIndicator.x = calculatedX + 1.5 * ApplicationInfo.ratio editInstructionIndicator.y = calculatedY + 1.5 * ApplicationInfo.ratio } } - else if((items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed) && instruction.instructionToInsert) + else if((items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed) && instructionArea.instructionToInsert) appendInstruction() } - Keys.onDeletePressed: { + + onDeleteKeyPressed: { if(currentIndex != -1) { currentModel.remove(currentIndex) items.numberOfInstructionsAdded-- @@ -120,10 +118,10 @@ } function appendInstruction() { - if(!(background.insertIntoProcedure && (instruction.instructionToInsert === "call-procedure"))) { - currentModel.append({ "name": instruction.instructionToInsert }) + if(background.insertIntoMain || (instructionArea.instructionToInsert != "call-procedure")) { + currentModel.append({ "name": instructionArea.instructionToInsert }) items.numberOfInstructionsAdded++ - instruction.instructionToInsert = "" + instructionArea.instructionToInsert = "" return true } return false @@ -135,7 +133,7 @@ } Item { - id: dropPosIndicator + id: dropPositionIndicator visible: false height: background.buttonHeight width: 3 * ApplicationInfo.ratio @@ -152,14 +150,14 @@ states: [ State { name: "shown" - when: answerSheet.possibleDropIndex != -1 + when: codeArea.possibleDropIndex != -1 PropertyChanges { - target: dropPosIndicator + target: dropPositionIndicator visible: true - x: Math.floor(answerSheet.xCoordinateInPossibleDrop / answerSheet.cellWidth) * - answerSheet.cellWidth - 1.5 * ApplicationInfo.ratio - y: Math.floor(answerSheet.yCoordinateInPossibleDrop / answerSheet.cellHeight) * - answerSheet.cellHeight + 1.5 * ApplicationInfo.ratio + x: Math.floor(codeArea.xCoordinateInPossibleDrop / codeArea.cellWidth) * + codeArea.cellWidth - 1.5 * ApplicationInfo.ratio + y: Math.floor(codeArea.yCoordinateInPossibleDrop / codeArea.cellHeight) * + codeArea.cellHeight + 1.5 * ApplicationInfo.ratio } } ] @@ -167,7 +165,7 @@ Rectangle { id: editInstructionIndicator - visible: answerSheet.isEditingInstruction && answerSheet.count != 0 + visible: codeArea.isEditingInstruction && codeArea.count != 0 width: background.buttonWidth - 3 * ApplicationInfo.ratio height: background.buttonHeight - 3 * ApplicationInfo.ratio color: "red" @@ -177,34 +175,46 @@ radius: width / 18 } - Item { - id: dndContainer - anchors.fill: parent - } - MouseArea { - id: coords + id: codeAreaMouse anchors.fill: parent enabled: items.isTuxMouseAreaEnabled || items.isRunCodeEnabled onPressed: { - answerSheet.draggedItemIndex = answerSheet.indexAt(mouseX,mouseY) - if(answerSheet.draggedItemIndex === -1) { + codeArea.draggedItemIndex = codeArea.indexAt(mouseX,mouseY) + if(codeArea.draggedItemIndex === -1) { constraintInstruction.changeConstraintInstructionOpacity() - answerSheet.isEditingInstruction = false + codeArea.isEditingInstruction = false } - else if(!answerSheet.isEditingInstruction) - answerSheet.initialEditItemIndex = answerSheet.draggedItemIndex + else if(!codeArea.isEditingInstruction) + codeArea.initialEditItemIndex = codeArea.draggedItemIndex } + + onPositionChanged: { + var newPos = codeArea.indexAt(mouseX, mouseY) + var calculatedX = Math.floor(mouseX / codeArea.cellWidth) * codeArea.cellWidth + var previousIndexPosition = codeArea.indexAt(calculatedX - 1, mouseY) + + // If the user want to move an item to the end, then the new position will be after the last instruction. + if(newPos == -1 && previousIndexPosition != -1) + newPos = previousIndexPosition + 1 + + codeArea.isEditingInstruction = false + codeArea.xCoordinateInPossibleDrop = mouseX + codeArea.yCoordinateInPossibleDrop = mouseY + codeArea.possibleDropIndex = newPos + } + onReleased: { - if(answerSheet.draggedItemIndex != -1) { - var draggedIndex = answerSheet.draggedItemIndex - var dropIndex = answerSheet.indexAt(mouseX,mouseY) - var calculatedX = Math.floor(mouseX / answerSheet.cellWidth) * answerSheet.cellWidth - var calculatedY = Math.floor(mouseY / answerSheet.cellHeight) * answerSheet.cellHeight - answerSheet.draggedItemIndex = -1 + if(codeArea.draggedItemIndex != -1) { + var draggedIndex = codeArea.draggedItemIndex + var dropIndex = codeArea.indexAt(mouseX,mouseY) + var calculatedX = Math.floor(mouseX / codeArea.cellWidth) * codeArea.cellWidth + var calculatedY = Math.floor(mouseY / codeArea.cellHeight) * codeArea.cellHeight + codeArea.draggedItemIndex = -1 + if(dropIndex == -1) { - var previousIndexCalculatedPosition = answerSheet.indexAt(calculatedX - 1, mouseY) - if(previousIndexCalculatedPosition == -1) { + var previousIndexPosition = codeArea.indexAt(calculatedX - 1, mouseY) + if(previousIndexPosition == -1) { currentModel.remove(draggedIndex) items.numberOfInstructionsAdded-- } @@ -212,47 +222,38 @@ currentModel.append(currentModel.get(draggedIndex)) currentModel.remove(draggedIndex) } - answerSheet.initialEditItemIndex = -1 + codeArea.initialEditItemIndex = -1 } else if(draggedIndex != dropIndex) { if(dropIndex <= draggedIndex) { - //moving box from right to left + // Moving instruction from right to left currentModel.move(draggedIndex, dropIndex, 1) } else { - //moving box from left to right + // Moving instruction from left to right currentModel.move(draggedIndex, dropIndex - 1, 1) } - answerSheet.initialEditItemIndex = -1 + codeArea.initialEditItemIndex = -1 } else { - if(answerSheet.initialEditItemIndex == dropIndex) { - answerSheet.isEditingInstruction = !answerSheet.isEditingInstruction - if(!answerSheet.isEditingInstruction) - answerSheet.initialEditItemIndex = -1 + /** + * If the index of the initially selected instruction (if any) is same as the currently selected instruction, + * deselect it for editing, else make the current instruction as the initially editable item and move the edit indicator to that position. + */ + if(codeArea.initialEditItemIndex == dropIndex) { + codeArea.isEditingInstruction = !codeArea.isEditingInstruction + if(!codeArea.isEditingInstruction) + codeArea.initialEditItemIndex = -1 } else - answerSheet.initialEditItemIndex = draggedIndex + codeArea.initialEditItemIndex = draggedIndex editInstructionIndicator.x = calculatedX + 1.5 * ApplicationInfo.ratio editInstructionIndicator.y = calculatedY + 1.5 * ApplicationInfo.ratio } - answerSheet.possibleDropIndex = -1 + codeArea.possibleDropIndex = -1 } } - onPositionChanged: { - var newPos = answerSheet.indexAt(mouseX, mouseY) - var calculatedX = Math.floor(mouseX / answerSheet.cellWidth) * answerSheet.cellWidth - var previousIndexCalculatedPosition = answerSheet.indexAt(calculatedX - 1, mouseY) - - //If the user want to move an item to the end, then the new position will be after the last instruction. - if(newPos == -1 && previousIndexCalculatedPosition != -1) - newPos = previousIndexCalculatedPosition + 1 - answerSheet.isEditingInstruction = false - answerSheet.xCoordinateInPossibleDrop = mouseX - answerSheet.yCoordinateInPossibleDrop = mouseY - answerSheet.possibleDropIndex = newPos - } } delegate: Item { @@ -284,23 +285,26 @@ states: [ State { name: "inDrag" - when: index == answerSheet.draggedItemIndex + when: index == codeArea.draggedItemIndex + PropertyChanges { target: circlePlaceholder; opacity: 1 } - PropertyChanges { target: item; parent: dndContainer } + PropertyChanges { target: item; parent: codeArea } PropertyChanges { target: item; width: background.buttonWidth * 0.80 } PropertyChanges { target: item; height: background.buttonHeight * 0.80 } PropertyChanges { target: item; anchors.centerIn: undefined } - PropertyChanges { target: item; x: coords.mouseX - item.width / 2 } - PropertyChanges { target: item; y: coords.mouseY - item.height / 2 } + PropertyChanges { target: item; x: codeAreaMouse.mouseX - item.width / 2 } + PropertyChanges { target: item; y: codeAreaMouse.mouseY - item.height / 2 } }, State { name: "greyedOut" - when: (answerSheet.draggedItemIndex != -1) && (answerSheet.draggedItemIndex != index) + when: (codeArea.draggedItemIndex != -1) && (codeArea.draggedItemIndex != index) + PropertyChanges { target: item; opacity: 0.7 } }, State { name: "inactive" - when: (answerSheet.draggedItemIndex == -1) || (answerSheet.draggedItemIndex == index) + when: (codeArea.draggedItemIndex == -1) || (codeArea.draggedItemIndex == index) + PropertyChanges { target: item; opacity: 1.0 } } ] diff --git a/src/activities/programmingMaze/ProgrammingMaze.qml b/src/activities/programmingMaze/ProgrammingMaze.qml --- a/src/activities/programmingMaze/ProgrammingMaze.qml +++ b/src/activities/programmingMaze/ProgrammingMaze.qml @@ -1,6 +1,7 @@ /* GCompris - ProgrammingMaze.qml * * Copyright (C) 2015 Siddhesh Suthar + * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar @@ -55,7 +56,6 @@ signal stop property bool insertIntoMain: true - property bool insertIntoProcedure: false property alias items: items property int buttonWidth: background.width / 10 property int buttonHeight: background.height / 15.3 @@ -79,7 +79,7 @@ property alias mainFunctionCodeArea: mainFunctionCodeArea property alias procedureModel: procedureModel property alias procedureCodeArea: procedureCodeArea - property alias instruction: instruction + property alias instructionArea: instructionArea property alias player: player property alias constraintInstruction: constraintInstruction property alias tutorialImage: tutorialImage @@ -91,12 +91,12 @@ property int numberOfInstructionsAdded } - //This function catches the signal emitted after completion of movement of Tux after executing each instruction. + // This function catches the signal emitted after completion of movement of Tux after executing each instruction. function currentInstructionExecutionComplete() { Activity.checkSuccessAndExecuteNextInstruction() } - //This function catches the signal emitted after finding a dead-end in any of the executing instruction. + // This function catches the signal emitted after finding a dead-end in any of the executing instruction. function deadEnd() { Activity.deadEnd() } @@ -106,55 +106,29 @@ } onStop: { Activity.stop() } - Keys.onRightPressed: { - activity.keyboardNavigationVisible = true - instruction.moveCurrentIndexRight() - } - Keys.onLeftPressed: { - activity.keyboardNavigationVisible = true - instruction.moveCurrentIndexLeft() - } - Keys.onDownPressed: { - activity.keyboardNavigationVisible = true - instruction.moveCurrentIndexDown() - } - Keys.onUpPressed: { - activity.keyboardNavigationVisible = true - instruction.moveCurrentIndexUp() - } - Keys.onSpacePressed: { - if(instruction.currentIndex != -1) - instruction.currentItem.mouseAreaInstruction.clicked() - } - Keys.onEnterPressed: runCodeOrResetTux() - Keys.onReturnPressed: runCodeOrResetTux() - Keys.onTabPressed: { - activity.keyboardNavigationVisible = true - changeFocus("main") - } + property var areaWithKeyboardInput: instructionArea - function changeFocus(currentCodeArea) { - if(currentCodeArea === "main") { - mainFunctionCodeArea.forceActiveFocus() - background.insertIntoMain = true - background.insertIntoProcedure = false - instruction.currentIndex = -1 - activeCodeAreaIndicator.changeActiveCodeAreaIndicator(mainFunctionCodeArea) - } - else if(currentCodeArea === "procedure") { - procedureCodeArea.forceActiveFocus() - background.insertIntoMain = false - background.insertIntoProcedure = true - mainFunctionCodeArea.currentIndex = -1 - activeCodeAreaIndicator.changeActiveCodeAreaIndicator(procedureCodeArea) - } - else if(currentCodeArea === "instruction") { - activity.forceActiveFocus() - background.insertIntoMain = true - background.insertIntoProcedure = false - Activity.resetCodeAreasIndices() - instruction.currentIndex = 0 - activeCodeAreaIndicator.changeActiveCodeAreaIndicator(instruction) + onAreaWithKeyboardInputChanged: activeCodeAreaIndicator.changeActiveCodeAreaIndicator(areaWithKeyboardInput) + + Keys.enabled: items.isTuxMouseAreaEnabled || items.isRunCodeEnabled + Keys.onPressed: { + activity.keyboardNavigationVisible = true + if(event.key === Qt.Key_Left) + areaWithKeyboardInput.moveCurrentIndexLeft() + if(event.key === Qt.Key_Right) + areaWithKeyboardInput.moveCurrentIndexRight() + if(event.key === Qt.Key_Up) + areaWithKeyboardInput.moveCurrentIndexUp() + if(event.key === Qt.Key_Down) + areaWithKeyboardInput.moveCurrentIndexDown() + if(event.key === Qt.Key_Space) + areaWithKeyboardInput.spaceKeyPressed() + if(event.key === Qt.Key_Enter || event.key === Qt.Key_Return) + runCodeOrResetTux() + if(event.key === Qt.Key_Tab) + areaWithKeyboardInput.tabKeyPressed() + if(event.key === Qt.Key_Delete && activeCodeAreaIndicator.top != instructionArea.top) { + areaWithKeyboardInput.deleteKeyPressed() } } @@ -257,13 +231,6 @@ property int duration: 1000 readonly property real playerCenterX: x + width / 2 readonly property real playerCenterY: y + height / 2 - rotation: 0 - - signal init - - onInit: { - player.rotation = Activity.EAST - } MouseArea { id: tuxMouseArea @@ -278,6 +245,7 @@ Rectangle { id: activeCodeAreaIndicator opacity: 0.5 + visible: activity.keyboardNavigationVisible function changeActiveCodeAreaIndicator(activeArea) { anchors.top = activeArea.top @@ -286,7 +254,7 @@ } GridView { - id: instruction + id: instructionArea width: parent.width * 0.5 height: parent.height * 0.17 cellWidth: background.buttonWidth @@ -303,6 +271,19 @@ property string instructionToInsert + signal spaceKeyPressed + signal tabKeyPressed + + onSpaceKeyPressed: { + if(instructionArea.currentIndex != -1) + instructionArea.currentItem.selectCurrentInstruction() + } + + onTabKeyPressed: { + instructionArea.currentIndex = -1 + background.areaWithKeyboardInput = mainFunctionCodeArea + } + highlight: Rectangle { width: buttonWidth - 3 * ApplicationInfo.ratio height: buttonHeight * 1.18 - 3 * ApplicationInfo.ratio @@ -319,13 +300,12 @@ keyNavigationWraps: true delegate: Item { + id: instructionItem width: background.buttonWidth height: background.buttonHeight * 1.18 - property alias mouseAreaInstruction: mouseAreaInstruction - Rectangle { - id: rect + id: imageHolder width: parent.width - 3 * ApplicationInfo.ratio height: parent.height - 3 * ApplicationInfo.ratio border.width: 1.2 * ApplicationInfo.ratio @@ -342,29 +322,38 @@ } MouseArea { - id: mouseAreaInstruction + id: mouseArea anchors.fill: parent enabled: (items.isTuxMouseAreaEnabled || items.isRunCodeEnabled) && (items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed || procedureCodeArea.isEditingInstruction || mainFunctionCodeArea.isEditingInstruction) - signal clicked + onPressed: instructionItem.checkModelAndInsert() + } - onClicked: { - if(!mainFunctionCodeArea.isEditingInstruction && !procedureCodeArea.isEditingInstruction) { - instruction.instructionToInsert = name - playClickedAnimation() - } - else { - if(mainFunctionCodeArea.isEditingInstruction) - replaceInstruction(mainFunctionModel, mainFunctionCodeArea) - if(procedureCodeArea.isEditingInstruction && name != "call-procedure") - replaceInstruction(procedureModel, procedureCodeArea) - } + function selectCurrentInstruction() { + if(!mainFunctionCodeArea.isEditingInstruction && !procedureCodeArea.isEditingInstruction) { + instructionArea.instructionToInsert = name + playClickedAnimation() } - onPressed: { + else checkModelAndInsert() - } + } - function appendInstruction(model, area) { + function checkModelAndInsert() { + if(items.constraintInstruction.opacity) + items.constraintInstruction.hide() + + if(!background.insertIntoMain && (name != Activity.CALL_PROCEDURE)) + insertIntoModel(procedureModel, procedureCodeArea) + else if(background.insertIntoMain) + insertIntoModel(mainFunctionModel, mainFunctionCodeArea) + } + + /** + * If we are adding an instruction, append it to the model if number of instructions added is less than the maximum number of instructions allowed. + * If editing, replace it with the selected instruction in the code area. + */ + function insertIntoModel(model, area) { + if(!area.isEditingInstruction) { if(items.numberOfInstructionsAdded >= items.maxNumberOfInstructionsAllowed) constraintInstruction.changeConstraintInstructionOpacity() else { @@ -373,57 +362,35 @@ items.numberOfInstructionsAdded++ } } - - function replaceInstruction(model, area) { + else { playClickedAnimation() model.set(area.initialEditItemIndex, {"name": name}, 1) area.resetEditingValues() } + } - function checkModelAndInsert() { - if(items.constraintInstruction.opacity) - items.constraintInstruction.hide() - - if(background.insertIntoProcedure && (name != Activity.CALL_PROCEDURE)) - insertIntoModel(procedureModel, procedureCodeArea) - else if(background.insertIntoMain) - insertIntoModel(mainFunctionModel, mainFunctionCodeArea) - } - - /** - * If we are adding an instruction, append it to the model if number of instructions added is less than the maximum number of instructions allowed. - * If editing, replace it with the selected instruction in the code area. - */ - function insertIntoModel(model, area) { - if(!area.isEditingInstruction) - appendInstruction(model, area) - else - replaceInstruction(model, area) - } - - /** - * If two successive clicks on the same icon are made very fast, stop the ongoing animation and set the scale back to 1. - * Then start the animation for next click. - * This gives proper feedback of multiple clicks. - */ - function playClickedAnimation() { - clickedAnim.stop() - icon.scale = 1 - clickedAnim.start() - } + /** + * If two successive clicks on the same icon are made very fast, stop the ongoing animation and set the scale back to 1. + * Then start the animation for next click. + * This gives proper feedback of multiple clicks. + */ + function playClickedAnimation() { + clickedAnimation.stop() + icon.scale = 1 + clickedAnimation.start() } SequentialAnimation { - id: clickedAnim + id: clickedAnimation PropertyAnimation { - target: rect + target: imageHolder property: "scale" to: 0.8 duration: 150 } PropertyAnimation { - target: rect + target: imageHolder property: "scale" to: 1 duration: 150 @@ -432,40 +399,47 @@ } } - // insert data upon clicking the list items into this answerData - // and then process it to run the code AnswerSheet { id: mainFunctionCodeArea - background: background currentModel: mainFunctionModel anchors.right: parent.right anchors.top: mainFunctionHeaderComponent.bottom - Keys.onTabPressed: { - if(!items.currentLevelContainsProcedure) - background.changeFocus("instruction") - else - background.changeFocus("procedure") + onTabKeyPressed: { + mainFunctionCodeArea.currentIndex = -1 + if(!items.currentLevelContainsProcedure) { + background.areaWithKeyboardInput = instructionArea + instructionArea.currentIndex = 0 + } + else { + background.areaWithKeyboardInput = procedureCodeArea + background.insertIntoMain = false + } } } AnswerSheet { id: procedureCodeArea - background: background currentModel: procedureModel anchors.right: parent.right anchors.top: procedureHeaderComponent.bottom visible: items.currentLevelContainsProcedure + property alias procedureIterator: procedureCodeArea.currentIndex - Keys.onTabPressed: background.changeFocus("instruction") + onTabKeyPressed: { + procedureCodeArea.currentIndex = -1 + background.areaWithKeyboardInput = instructionArea + instructionArea.currentIndex = 0 + background.insertIntoMain = true + } } Image { id: runCode width: background.width / 10 height: background.height / 10 - anchors.right: instruction.right + anchors.right: instructionArea.right anchors.bottom: bar.top anchors.margins: 10 * ApplicationInfo.ratio @@ -510,7 +484,7 @@ id: instructionHeaderComponent Rectangle { id: instructionHeaderRectangle - width: instruction.width + width: instructionArea.width height: background.height / 11 border.width: 2 * ApplicationInfo.ratio border.color: "black" @@ -563,10 +537,7 @@ MouseArea { anchors.fill: parent enabled: items.isTuxMouseAreaEnabled || items.isRunCodeEnabled - onClicked: { - background.insertIntoMain = true - background.insertIntoProcedure = false - } + onClicked: background.insertIntoMain = true } GCText { @@ -605,15 +576,12 @@ source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW02.svg" x: parent.border.width y: x - opacity: background.insertIntoProcedure ? 1 : 0.5 + opacity: !background.insertIntoMain ? 1 : 0.5 MouseArea { anchors.fill: parent enabled: items.isTuxMouseAreaEnabled || items.isRunCodeEnabled - onClicked: { - background.insertIntoMain = false - background.insertIntoProcedure = true - } + onClicked: background.insertIntoMain = false } GCText { diff --git a/src/activities/programmingMaze/programmingMaze.js b/src/activities/programmingMaze/programmingMaze.js --- a/src/activities/programmingMaze/programmingMaze.js +++ b/src/activities/programmingMaze/programmingMaze.js @@ -1,6 +1,7 @@ /* GCompris - programmingMaze.js * * Copyright (C) 2015 Siddhesh Suthar + * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar @@ -313,13 +314,13 @@ } /** - * The procedure function's object. This object is linked to all its instructions with signal and slot. + * The procedure function's object. This is a centralised procedure object and will be linked to all its instructions with signal and slot. * * Since the signals of instructions created in procedureCode need to be connected to the procedure file, * hence only one object for procedure function is sufficient and this same - * procedure object will be re-used to push into the main code when the code is run. + * procedure object will be re-used to push into the main code whenever the procedure call is made. */ -var procedureFunctionObject +var procedureObject var mainTutorialInstructions = [ { @@ -360,6 +361,33 @@ destroyInstructionObjects() } +/** + * This function creates a single centralised and re-usable set of procedureObject and the procedure instructions. + * The procedure instructions are then connected to the procedureObject (object of the procedure file). + * + * These can be accessed wherever required to execute the procedure and saves the process of re-creating all the instruction objets, + * connecting them to the procedure's slot and destroying them everytime for each function call which will be very redundant + * and quite memory consuming on devices with less RAM, weak processing power and slow performance. + * + * Hence these centralised objects will be created and destroyed only once in each level (depending on the need) and can be accessed when needed. + */ +function createProcedureObjects() { + procedureObject = instructionComponents[CALL_PROCEDURE].createObject(items.background) + procedureCode[MOVE_FORWARD] = instructionComponents[MOVE_FORWARD].createObject(procedureObject) + procedureCode[TURN_LEFT] = instructionComponents[TURN_LEFT].createObject(procedureObject, { "turnDirection": "turn-left" }) + procedureCode[TURN_RIGHT] = instructionComponents[TURN_RIGHT].createObject(procedureObject, { "turnDirection": "turn-right" }) + + procedureObject.foundDeadEnd.connect(items.background.deadEnd) + procedureObject.executionComplete.connect(items.background.currentInstructionExecutionComplete) + + var procedureInstructions = Object.keys(procedureCode) + + for(var i = 0; i < procedureInstructions.length; i++) { + procedureCode[procedureInstructions[i]].foundDeadEnd.connect(procedureObject.deadEnd) + procedureCode[procedureInstructions[i]].executionComplete.connect(procedureObject.checkSuccessAndExecuteNextInstruction) + } +} + function destroyInstructionObjects() { for(var i = 0; i < mainFunctionCode.length; i++) { mainFunctionCode[i].destroy() @@ -368,7 +396,7 @@ procedureCode[MOVE_FORWARD].destroy() procedureCode[TURN_LEFT].destroy() procedureCode[TURN_RIGHT].destroy() - procedureFunctionObject.destroy() + procedureObject.destroy() } mainFunctionCode = [] @@ -382,9 +410,6 @@ items.bar.level = currentLevel + 1 destroyInstructionObjects() - items.mainFunctionCodeArea.currentIndex = -1 - items.procedureCodeArea.procedureIterator = -1 - var levelInstructions = mazeBlocks[currentLevel].instructions if(levelInstructions.indexOf(CALL_PROCEDURE) != -1) @@ -392,29 +417,13 @@ else items.currentLevelContainsProcedure = false - //In the levels where there are procedure code area, create instructions for it and connect the instructions' signals to procedureFunctionObject's slots. + //In the levels where there are procedure code area, create instructions for it and connect the instructions' signals to procedureObject's slots. if(items.currentLevelContainsProcedure) { if(!items.tutorialImage.shownProcedureTutorialInstructions) { items.tutorialImage.shownProcedureTutorialInstructions = true items.tutorialImage.visible = true } - - procedureFunctionObject = instructionComponents[CALL_PROCEDURE].createObject(items.background) - procedureCode[MOVE_FORWARD] = instructionComponents[MOVE_FORWARD].createObject(procedureFunctionObject) - procedureCode[TURN_LEFT] = instructionComponents[TURN_LEFT].createObject(procedureFunctionObject, { "turnDirection": "turn-left" }) - procedureCode[TURN_RIGHT] = instructionComponents[TURN_RIGHT].createObject(procedureFunctionObject, { "turnDirection": "turn-right" }) - - procedureFunctionObject.foundDeadEnd.connect(items.background.deadEnd) - procedureFunctionObject.executionComplete.connect(items.background.currentInstructionExecutionComplete) - - procedureCode[MOVE_FORWARD].foundDeadEnd.connect(procedureFunctionObject.deadEnd) - procedureCode[MOVE_FORWARD].executionComplete.connect(procedureFunctionObject.checkSuccessAndExecuteNextInstruction) - - procedureCode[TURN_LEFT].foundDeadEnd.connect(procedureFunctionObject.deadEnd) - procedureCode[TURN_LEFT].executionComplete.connect(procedureFunctionObject.checkSuccessAndExecuteNextInstruction) - - procedureCode[TURN_RIGHT].foundDeadEnd.connect(procedureFunctionObject.deadEnd) - procedureCode[TURN_RIGHT].executionComplete.connect(procedureFunctionObject.checkSuccessAndExecuteNextInstruction) + createProcedureObjects() } // Stores the co-ordinates of the tile blocks in the current level @@ -440,8 +449,9 @@ // Center Tux in its first case items.player.x = currentLevelBlocksCoordinates[0].x * stepX + (stepX - items.player.width) / 2 items.player.y = currentLevelBlocksCoordinates[0].y * stepY + (stepY - items.player.height) / 2 + items.player.rotation = EAST - //Center fish at it's co-ordinate + // Center fish at it's co-ordinate items.fish.x = mazeBlocks[currentLevel].fish.x * stepX + (stepX - items.fish.width) / 2 items.fish.y = mazeBlocks[currentLevel].fish.y * stepY + (stepY - items.fish.height) / 2 @@ -449,7 +459,6 @@ deadEndPoint = false moveAnimDuration = 1000 items.background.insertIntoMain = true - items.background.insertIntoProcedure = false items.mainFunctionCodeArea.highlightMoveDuration = moveAnimDuration / 2 items.procedureCodeArea.highlightMoveDuration = moveAnimDuration / 2 items.isTuxMouseAreaEnabled = false @@ -458,31 +467,28 @@ items.constraintInstruction.show() items.mainFunctionCodeArea.resetEditingValues() items.procedureCodeArea.resetEditingValues() + items.background.areaWithKeyboardInput = items.instructionArea resetCodeAreasIndices() - items.background.changeFocus("instruction") resetTux = false codeIterator = 0 - - items.player.init() } function resetCodeAreasIndices() { - items.instruction.currentIndex = -1 + items.instructionArea.currentIndex = -1 items.mainFunctionCodeArea.currentIndex = -1 items.procedureCodeArea.currentIndex = -1 - items.instruction.instructionToInsert = '' + items.instructionArea.instructionToInsert = '' } function getPlayerRotation() { return ((changedRotation % 360) + 360) % 360 } -//store all the instructions from main and procedure areas in their respective instruction lists. +// Store all the instructions from main and procedure areas in their respective instruction lists. function runCode() { items.mainFunctionCodeArea.resetEditingValues() items.procedureCodeArea.resetEditingValues() - //initialize code mainFunctionCode = [] var instructionName @@ -491,7 +497,8 @@ /** * Create and append objects of all the instructions in the main area code. * - * If the instruction is call-procedure, append the procedureFunctionObject, and it will access the instructions created in procedureCode which are linked to this object. + * If the instruction is call-procedure, append the procedureObject, and it will in turn execute the centralised + * instructions created in procedureCode which are linked to this object. */ for(var i = 0; i < items.mainFunctionModel.count; i++) { instructionName = items.mainFunctionModel.get([i]).name @@ -509,14 +516,14 @@ mainFunctionCode.push(instructionObject) } else { - mainFunctionCode.push(procedureFunctionObject) + mainFunctionCode.push(procedureObject) } } - //Append all the instructions from the procedure area. + // Append all the instructions from the procedure area to the procedureObject. for(var j = 0; j < items.procedureModel.count; j++) { instructionName = items.procedureModel.get([j]).name - procedureFunctionObject.procedureCode.append({ "name" : instructionName }) + procedureObject.procedureCode.append({ "name" : instructionName }) } items.isRunCodeEnabled = false