Warning, /education/gcompris/src/activities/melody/Melody.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - melody.qml 0002 * 0003 * SPDX-FileCopyrightText: 2015 Bruno Coudoin <bruno.coudoin@gcompris.net> 0004 * 0005 * Authors: 0006 * Jose JORGE <jjorge@free.fr> (GTK+ version) 0007 * Bruno Coudoin <bruno.coudoin@gcompris.net> (Qt Quick port) 0008 * 0009 * SPDX-License-Identifier: GPL-3.0-or-later 0010 */ 0011 import QtQuick 2.12 0012 import GCompris 1.0 0013 0014 import "../../core" 0015 import "qrc:/gcompris/src/core/core.js" as Core 0016 0017 ActivityBase { 0018 id: activity 0019 0020 onStart: focus = true 0021 onStop: {} 0022 isMusicalActivity: true 0023 0024 pageComponent: Rectangle { 0025 id: background 0026 anchors.fill: parent 0027 color: "#ABCDEF" 0028 0029 // if audio is disabled, we display a dialog to tell users this activity requires audio anyway 0030 property bool audioDisabled: false 0031 0032 signal start 0033 signal stop 0034 0035 Component.onCompleted: { 0036 activity.start.connect(start) 0037 activity.stop.connect(stop) 0038 } 0039 0040 // Add here the QML items you need to access in javascript 0041 QtObject { 0042 id: items 0043 property string url: "qrc:/gcompris/src/activities/melody/resource/" 0044 property var question 0045 property var questionToPlay 0046 property var answer 0047 property alias questionInterval: questionPlayer.interval 0048 readonly property int numberOfLevel: 10 0049 property int currentLevel: 0 0050 property bool running: false 0051 property bool buttonsBlocked: false 0052 } 0053 0054 onStart: { 0055 items.currentLevel = Core.getInitialLevel(items.numberOfLevel); 0056 score.numberOfSubLevels = 5; 0057 score.currentSubLevel = 0; 0058 if(!ApplicationSettings.isAudioVoicesEnabled || !ApplicationSettings.isAudioEffectsEnabled) { 0059 background.audioDisabled = true; 0060 } else { 0061 initLevel(); 0062 items.running = true; 0063 introDelay.start(); 0064 } 0065 } 0066 0067 onStop: { 0068 introDelay.stop() 0069 knock.stop() 0070 questionPlayer.stop() 0071 items.running = false 0072 } 0073 0074 Item { 0075 id: layoutArea 0076 width: parent.width 0077 height: parent.height - bar.height * 1.5 - score.height * 1.3 0078 anchors.top: score.bottom 0079 anchors.left: parent.left 0080 } 0081 0082 Image { 0083 id: xylofon 0084 anchors { 0085 fill: layoutArea 0086 margins: 10 * ApplicationInfo.ratio 0087 } 0088 source: items.url + 'xylofon.svg' 0089 sourceSize.width: width 0090 sourceSize.height: height 0091 fillMode: Image.PreserveAspectFit 0092 } 0093 0094 Repeater { 0095 id: parts 0096 model: 4 0097 Image { 0098 id: part 0099 source: items.url + 'xylofon_part' + (index + 1) + '.svg' 0100 rotation: - 80 0101 anchors.horizontalCenter: xylofon.horizontalCenter 0102 anchors.horizontalCenterOffset: (- xylofon.paintedWidth) * 0.3 + xylofon.paintedWidth * index * 0.22 0103 anchors.verticalCenter: xylofon.verticalCenter 0104 anchors.verticalCenterOffset: - xylofon.paintedHeight * 0.1 0105 sourceSize.width: xylofon.paintedWidth * 0.5 0106 fillMode: Image.PreserveAspectFit 0107 0108 property alias anim: anim 0109 0110 SequentialAnimation { 0111 id: anim 0112 NumberAnimation { 0113 target: part 0114 property: "scale" 0115 from: 1; to: 0.95 0116 duration: 150 0117 easing.type: Easing.InOutQuad 0118 } 0119 NumberAnimation { 0120 target: part 0121 property: "scale" 0122 from: 0.95; to: 1 0123 duration: 150 0124 easing.type: Easing.OutElastic 0125 } 0126 } 0127 0128 MouseArea { 0129 anchors.fill: parent 0130 enabled: !questionPlayer.running && !knock.running && !introDelay.running 0131 && !anim.running && !items.buttonsBlocked 0132 onClicked: { 0133 anim.start() 0134 background.playNote(index) 0135 items.answer.push(index) 0136 if(items.answer.length >= items.question.length) { 0137 items.buttonsBlocked = true; 0138 feedbackTimer.restart(); 0139 } 0140 } 0141 } 0142 } 0143 } 0144 0145 function playNote(index) { 0146 activity.audioEffects.play(ApplicationInfo.getAudioFilePath(items.url + 0147 'xylofon_son' + (index + 1) + ".wav")) 0148 } 0149 Timer { 0150 id: introDelay 0151 interval: 1000 0152 repeat: false 0153 onTriggered: { 0154 if(activity.audioVoices.playbackState == 1) { 0155 introDelay.restart() 0156 } 0157 else { 0158 parent.repeat() 0159 } 0160 } 0161 } 0162 0163 0164 Timer { 0165 id: knock 0166 interval: 1000 0167 repeat: false 0168 onTriggered: { 0169 questionPlayer.start() 0170 } 0171 } 0172 0173 Timer { 0174 id: questionPlayer 0175 onTriggered: { 0176 var partIndex = items.questionToPlay.shift() 0177 if(partIndex !== undefined) { 0178 parts.itemAt(partIndex).anim.start() 0179 background.playNote(partIndex) 0180 start() 0181 } 0182 } 0183 } 0184 0185 Timer { 0186 id: feedbackTimer 0187 interval: 500 0188 onTriggered: { 0189 background.checkAnswer() 0190 } 0191 } 0192 0193 ErrorRectangle { 0194 id: errorRectangle 0195 anchors.fill: layoutArea 0196 imageSize: 60 * ApplicationInfo.ratio 0197 function releaseControls() { 0198 introDelay.restart(); 0199 items.buttonsBlocked = false; 0200 } 0201 } 0202 0203 DialogHelp { 0204 id: dialogHelp 0205 onClose: home() 0206 } 0207 0208 Bar { 0209 id: bar 0210 level: items.currentLevel + 1 0211 content: BarEnumContent { value: help | home | level | repeat } 0212 onHelpClicked: { 0213 displayDialog(dialogHelp) 0214 } 0215 onPreviousLevelClicked: { 0216 score.stopWinAnimation(); 0217 score.currentSubLevel = 0; 0218 items.currentLevel = Core.getPreviousLevel(items.currentLevel, items.numberOfLevel); 0219 initLevel(); 0220 parent.repeat(); 0221 } 0222 onNextLevelClicked: { 0223 parent.nextLevel(); 0224 parent.repeat(); 0225 } 0226 onHomeClicked: activity.home() 0227 onRepeatClicked: parent.repeat() 0228 } 0229 0230 Bonus { 0231 id: bonus 0232 onWin: { 0233 parent.nextLevel(); 0234 introDelay.restart(); 0235 } 0236 } 0237 0238 Score { 0239 id: score 0240 anchors.bottom: undefined 0241 anchors.right: parent.right 0242 anchors.rightMargin: 10 * ApplicationInfo.ratio 0243 anchors.top: parent.top 0244 onStop: { 0245 parent.nextSubLevel(); 0246 introDelay.restart(); 0247 } 0248 } 0249 0250 function initLevel() { 0251 errorRectangle.resetState(); 0252 items.question = [] 0253 questionPlayer.stop() 0254 0255 var numberOfParts = 4 0256 if(items.currentLevel < 2) 0257 numberOfParts = 2 0258 else if(items.currentLevel < 4) 0259 numberOfParts = 3 0260 0261 for(var i = 0; i < items.currentLevel + 3; ++i) { 0262 items.question.push(Math.floor(Math.random() * numberOfParts)) 0263 } 0264 items.questionInterval = 1200 - Math.min(500, 100 * (items.currentLevel + 1)) 0265 items.answer = [] 0266 items.buttonsBlocked = false 0267 } 0268 0269 function nextSubLevel() { 0270 if(score.currentSubLevel < score.numberOfSubLevels) { 0271 initLevel() 0272 return 0273 } 0274 bonus.good("note") 0275 } 0276 0277 function nextLevel() { 0278 score.stopWinAnimation(); 0279 score.currentSubLevel = 0; 0280 items.currentLevel = Core.getNextLevel(items.currentLevel, items.numberOfLevel); 0281 initLevel(); 0282 } 0283 0284 function repeat() { 0285 if(items.running == true) { 0286 introDelay.stop() 0287 activity.audioVoices.stop() 0288 questionPlayer.stop() 0289 activity.audioEffects.play(ApplicationInfo.getAudioFilePath(items.url + 'knock.wav')) 0290 items.questionToPlay = items.question.slice() 0291 items.answer = [] 0292 knock.start() 0293 } 0294 } 0295 0296 function checkAnswer() { 0297 if(items.answer.join() == items.question.join()) { 0298 score.currentSubLevel += 1 0299 score.playWinAnimation() 0300 activity.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/completetask.wav") 0301 } else { 0302 activity.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/crash.wav") 0303 errorRectangle.startAnimation() 0304 } 0305 } 0306 0307 Loader { 0308 id: audioNeededDialog 0309 sourceComponent: GCDialog { 0310 parent: activity 0311 isDestructible: false 0312 message: qsTr("This activity requires sound, so it will play some sounds even if the audio voices or effects are disabled in the main configuration.") 0313 button1Text: qsTr("Quit") 0314 button2Text: qsTr("Continue") 0315 onButton1Hit: activity.home(); 0316 onClose: { 0317 background.audioDisabled = false; 0318 initLevel(); 0319 items.running = true; 0320 introDelay.start(); 0321 } 0322 } 0323 anchors.fill: parent 0324 focus: true 0325 active: background.audioDisabled 0326 onStatusChanged: if (status == Loader.Ready) item.start() 0327 } 0328 } 0329 }