diff --git a/src/activities/programmingMaze/ProgrammingMaze.qml b/src/activities/programmingMaze/ProgrammingMaze.qml index 3ae528659..4fc70d0b4 100644 --- a/src/activities/programmingMaze/ProgrammingMaze.qml +++ b/src/activities/programmingMaze/ProgrammingMaze.qml @@ -1,410 +1,410 @@ /* GCompris - ProgrammingMaze.qml * * Copyright (C) 2015 Siddhesh Suthar * Copyright (C) 2018 Aman Kumar Gupta * * Authors: * Siddhesh Suthar * 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 * 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.6 import GCompris 1.0 import "../../core" import "programmingMaze.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} property int oldWidth: width onWidthChanged: { Activity.repositionObjectsOnWidthChanged(width / oldWidth) oldWidth = width } property int oldHeight: height onHeightChanged: { Activity.repositionObjectsOnHeightChanged(height / oldHeight) oldHeight = height } property bool keyboardNavigationVisible: false property string mode: "basic" property string datasetUrl: "qrc:/gcompris/src/activities/programmingMaze/Dataset.qml" pageComponent: Image { id: background source: "qrc:/gcompris/src/activities/programmingMaze/resource/background.svg" fillMode: Image.PreserveAspectCrop sourceSize.width: parent.width signal start signal stop property bool insertIntoMain: true property alias items: items property int buttonWidth: background.width / 10 property int buttonHeight: background.height / 15.3 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 GCSfx audioEffects: activity.audioEffects property alias mazeModel: mazeModel property alias instructionModel: instructionModel property alias mainFunctionModel: mainFunctionModel property alias mainFunctionCodeArea: mainFunctionCodeArea property alias procedureModel: procedureModel property alias procedureCodeArea: procedureCodeArea property alias instructionArea: instructionArea property alias player: player property alias constraintInstruction: constraintInstruction property alias tutorialImage: tutorialImage property alias fish: fish property alias dataset: dataset property bool isRunCodeEnabled: true property bool isTuxMouseAreaEnabled: false property bool currentLevelContainsProcedure property int maxNumberOfInstructionsAllowed property int numberOfInstructionsAdded } // This function catches the signal emitted after completion of movement of Tux after executing each instruction. function checkSuccessAndExecuteNextInstruction() { Activity.checkSuccessAndExecuteNextInstruction() } // This function catches the signal emitted after finding a dead-end in any of the executing instruction. function deadEnd() { Activity.deadEnd() } Loader { id: dataset } onStart: { Activity.start(items, mode, datasetUrl) } onStop: { Activity.stop() } property var areaWithKeyboardInput: instructionArea 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() } } function runCodeOrResetTux() { if(!Activity.deadEndPoint) runCodeMouseArea.executeCode() else Activity.initLevel() } ListModel { id: instructionModel } ListModel { id: mainFunctionModel } ListModel { id: procedureModel } Rectangle { id: constraintInstruction anchors.left: parent.left anchors.bottom: runCode.top width: parent.width / 2.3 height: parent.height / 8.9 radius: 10 z: 3 color: "#E8E8E8" //paper white border.width: 3 * ApplicationInfo.ratio border.color: "#87A6DD" //light blue Behavior on opacity { PropertyAnimation { duration: 200 } } function changeConstraintInstructionOpacity() { if(opacity) constraintInstruction.hide() else constraintInstruction.show() } function show() { if(instructionText.text) opacity = 0.8 } function hide() { opacity = 0 } GCText { id: instructionText anchors.fill: parent anchors.margins: parent.border.width horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit wrapMode: Text.WordWrap readonly property string resetTuxInstructionText: qsTr("Click on Tux or press Enter key to reset it or RELOAD button to reload the level.") readonly property string constraintInstructionText: qsTr("Reach the fish in less than %1 instructions.").arg(items.maxNumberOfInstructionsAllowed + 1) text: items.isTuxMouseAreaEnabled ? resetTuxInstructionText : constraintInstructionText } } MouseArea { anchors.fill: parent onClicked: constraintInstruction.changeConstraintInstructionOpacity() } Repeater { id: mazeModel anchors.left: parent.left anchors.top: parent.top Image { x: modelData.x * width y: modelData.y * height width: background.width / 10 height: (background.height - background.height / 10) / 10 source: Activity.reverseCountUrl + "ice-block.svg" } } Image { id: fish sourceSize.width: background.width / 12 - source: Activity.reverseCountUrl + "blue-fish.svg" + source: Activity.reverseCountUrl + "fish-blue.svg" } Image { id: player source: "qrc:/gcompris/src/activities/maze/resource/tux_top_south.svg" sourceSize.width: background.width / 12 z: 1 property int duration: 1000 readonly property real playerCenterX: x + width / 2 readonly property real playerCenterY: y + height / 2 MouseArea { id: tuxMouseArea anchors.fill: parent enabled: items.isTuxMouseAreaEnabled onClicked: { Activity.initLevel() } } } Rectangle { id: activeCodeAreaIndicator opacity: 0.5 visible: activity.keyboardNavigationVisible function changeActiveCodeAreaIndicator(activeArea) { anchors.top = activeArea.top anchors.fill = activeArea } } InstructionArea { id: instructionArea } HeaderArea { id: mainFunctionHeader headerText: qsTr("Main function") headerOpacity: background.insertIntoMain ? 1 : 0.5 onClicked: background.insertIntoMain = true anchors.top: parent.top anchors.right: parent.right } CodeArea { id: mainFunctionCodeArea currentModel: mainFunctionModel anchors.right: parent.right anchors.top: mainFunctionHeader.bottom onTabKeyPressed: { mainFunctionCodeArea.currentIndex = -1 if(!items.currentLevelContainsProcedure) { background.areaWithKeyboardInput = instructionArea instructionArea.currentIndex = 0 } else { background.areaWithKeyboardInput = procedureCodeArea background.insertIntoMain = false } } } HeaderArea { id: procedureHeader headerText: qsTr("Procedure") headerOpacity: !background.insertIntoMain ? 1 : 0.5 visible: procedureCodeArea.visible onClicked: background.insertIntoMain = false anchors.top: mainFunctionCodeArea.bottom anchors.right: parent.right } CodeArea { id: procedureCodeArea currentModel: procedureModel anchors.right: parent.right anchors.top: procedureHeader.bottom visible: items.currentLevelContainsProcedure property alias procedureIterator: procedureCodeArea.currentIndex 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: instructionArea.right anchors.bottom: bar.top anchors.margins: 10 * ApplicationInfo.ratio source:"qrc:/gcompris/src/core/resource/bar_ok.svg" fillMode: Image.PreserveAspectFit MouseArea { id: runCodeMouseArea anchors.fill: parent hoverEnabled: ApplicationInfo.isMobile ? false : (!items.isRunCodeEnabled ? false : true) enabled: items.isRunCodeEnabled signal executeCode onEntered: runCode.scale = 1.1 onExecuteCode: { if(mainFunctionModel.count) startCodeExecution() } onClicked: executeCode() onExited: runCode.scale = 1 function startCodeExecution() { runCodeClickAnimation.start() Activity.resetCodeAreasIndices() if(constraintInstruction.opacity) constraintInstruction.hide() Activity.runCode() } } SequentialAnimation { id: runCodeClickAnimation NumberAnimation { target: runCode; property: "scale"; to: 0.8; duration: 100 } NumberAnimation { target: runCode; property: "scale"; to: 1.0; duration: 100 } } } Image { id: tutorialImage source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg" anchors.fill: parent z: 5 visible: true property bool shownProcedureTutorialInstructions: false Tutorial { id:tutorialSection tutorialDetails: bar.level <= 2 ? Activity.mainTutorialInstructions : Activity.procedureTutorialInstructions onSkipPressed: { Activity.initLevel() tutorialImage.visible = false tutorialNumber = 0 } } onVisibleChanged: { if(tutorialImage.visible && tutorialImage.shownProcedureTutorialInstructions) tutorialSection.visible = true } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: tutorialImage.visible ? help | home : help | home | level | reload } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reloadLevel() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/reversecount/Reversecount.qml b/src/activities/reversecount/Reversecount.qml index 533240ec0..7ae62697b 100644 --- a/src/activities/reversecount/Reversecount.qml +++ b/src/activities/reversecount/Reversecount.qml @@ -1,281 +1,280 @@ /* GCompris - ReverseCount.qml * * Copyright (C) 2014 Emmanuel Charruau * * Authors: * Bruno Coudoin (GTK+ version) * Emmanuel Charruau (Qt Quick port) * Bruno Coudoin (Major rework) * Timothée Giet (Layout and graphics rework) * * 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.6 import GCompris 1.0 import "../../core" import "reversecount.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent color: "#ff1dade4" signal start signal stop Component.onCompleted: { dialogActivityConfig.getInitialConfiguration() 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 GCSfx audioEffects: activity.audioEffects property alias background: background property alias bar: bar property alias bonus: bonus property alias chooseDiceBar: chooseDiceBar property alias tux: tux property alias fishToReach: fishToReach property int clockPosition: 4 property string mode: "dot" property var heightBase: (background.height - bar.height * 1.5) / 5 property var widthBase: background.width / 5 - property bool isHorizontal: background.width >= background.height } onStart: { Activity.start(items) } onStop: { Activity.stop() } Keys.onEnterPressed: Activity.moveTux() Keys.onReturnPressed: Activity.moveTux() onWidthChanged: { sizeChangedTimer.restart() } onHeightChanged: { sizeChangedTimer.restart() } function replaceItems() { if(Activity.fishIndex > 0) { // set x fishToReach.x = Activity.iceBlocksLayout[Activity.fishIndex % Activity.iceBlocksLayout.length][0] * items.widthBase + (items.widthBase - fishToReach.width) / 2 // set y fishToReach.y = Activity.iceBlocksLayout[Activity.fishIndex % Activity.iceBlocksLayout.length][1] * items.heightBase + (items.heightBase - fishToReach.height) / 2 // Move Tux Activity.moveTuxToIceBlock() } } Timer { id: sizeChangedTimer interval: 100 onTriggered: replaceItems() } // === The ice blocks === Repeater { model: Activity.iceBlocksLayout Image { x: modelData[0] * items.widthBase y: modelData[1] * items.heightBase width: items.widthBase height: items.heightBase source: Activity.url + "ice-block.svg" } } Tux { id: tux sourceSize.width: Math.min(items.widthBase, items.heightBase) z: 11 } Image { id: fishToReach source: Activity.url + "fish-blue.svg" sourceSize.width: Math.min(items.widthBase, items.heightBase) z: 10 property int nextX property int nextY function showParticles() { particles.burst(40) } ParticleSystemStarLoader { id: particles clip: false } onOpacityChanged: { if(opacity == 0) { x = nextX y = nextY opacity = 1 } } Behavior on opacity { NumberAnimation { duration: 500 } } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level | config } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onConfigClicked: { dialogActivityConfig.active = true dialogActivityConfig.setDefaultValues() displayDialog(dialogActivityConfig) } } Image { id: clock anchors { right: parent.right bottom: parent.bottom margins: 10 } sourceSize.width: 66 * bar.barZoom property int remainingLife: items.clockPosition onRemainingLifeChanged: if(remainingLife >= 0) clockAnim.restart() SequentialAnimation { id: clockAnim alwaysRunToEnd: true ParallelAnimation { NumberAnimation { target: clock; properties: "opacity"; to: 0; duration: 800; easing.type: Easing.OutCubic } NumberAnimation { target: clock; properties: "rotation"; from: 0; to: 180; duration: 800; easing.type: Easing.OutCubic } } PropertyAction { target: clock; property: 'source'; value: "qrc:/gcompris/src/activities/reversecount/resource/" + "flower" + items.clockPosition + ".svg" } ParallelAnimation { NumberAnimation { target: clock; properties: "opacity"; to: 1; duration: 800; easing.type: Easing.OutCubic } NumberAnimation { target: clock; properties: "rotation"; from: 180; to: 0; duration: 800; easing.type: Easing.OutCubic } } } } DialogActivityConfig { id: dialogActivityConfig currentActivity: activity content: Component { Item { property alias modeBox: modeBox property var availableModes: [ { "text": qsTr("Dots"), "value": "dot" }, { "text": qsTr("Arabic numbers"), "value": "number" }, { "text": qsTr("Roman numbers"), "value": "roman" }, { "text": qsTr("Images"), "value": "image" } ] Flow { id: flow spacing: 5 width: dialogActivityConfig.width GCComboBox { id: modeBox model: availableModes background: dialogActivityConfig label: qsTr("Select Domino Representation") } } } } onClose: home() onLoadData: { if(dataToSave && dataToSave["mode"]) { items.mode = dataToSave["mode"]; } } onSaveData: { var newMode = dialogActivityConfig.configItem.availableModes[dialogActivityConfig.configItem.modeBox.currentIndex].value; if (newMode !== items.mode) { items.mode = newMode; dataToSave = {"mode": items.mode}; } Activity.initLevel(); } function setDefaultValues() { for(var i = 0 ; i < dialogActivityConfig.configItem.availableModes.length ; i++) { if(dialogActivityConfig.configItem.availableModes[i].value === items.mode) { dialogActivityConfig.configItem.modeBox.currentIndex = i; break; } } } } ChooseDiceBar { id: chooseDiceBar mode: items.mode anchors.horizontalCenter: items.background.horizontalCenter y: items.heightBase * 2 audioEffects: activity.audioEffects } Bonus { id: bonus winSound: "qrc:/gcompris/src/activities/ballcatch/resource/tuxok.wav" looseSound: "qrc:/gcompris/src/activities/ballcatch/resource/youcannot.wav" onWin: Activity.nextLevel() onLoose: Activity.initLevel() } } }