Warning, /education/gcompris/src/activities/click_on_letter/ClickOnLetter.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - ClickOnLetter.qml 0002 * 0003 * SPDX-FileCopyrightText: 2014 Holger Kaelberer <holger.k@elberer.de> 0004 * 0005 * Authors: 0006 * Pascal Georges <pascal.georges1@free.fr> (GTK+ version) 0007 * Bruno Coudoin <bruno.coudoin@gcompris.net> (GTK+ Mostly full rewrite) 0008 * Holger Kaelberer <holger.k@elberer.de> (Qt Quick port) 0009 * 0010 * SPDX-License-Identifier: GPL-3.0-or-later 0011 */ 0012 0013 import QtQuick 2.12 0014 import GCompris 1.0 0015 import "../../core" 0016 import "click_on_letter.js" as Activity 0017 import "qrc:/gcompris/src/core/core.js" as Core 0018 0019 ActivityBase { 0020 id: activity 0021 focus: true 0022 0023 /* mode of the activity, either "lowercase" (click_on_letter) 0024 * or "uppercase" (click_on_letter_up): */ 0025 property string mode: "lowercase" 0026 0027 onStart: focus = true 0028 0029 // When opening a dialog, it steals the focus and re set it to the activity. 0030 // We need to set it back to the eventHandler item in order to have key events. 0031 onFocusChanged: { 0032 if(focus) { 0033 Activity.focusEventHandler() 0034 } 0035 } 0036 0037 pageComponent: Image { 0038 id: background 0039 source: Activity.url + "background.svg" 0040 sourceSize.width: width 0041 sourceSize.height: height 0042 fillMode: Image.PreserveAspectCrop 0043 focus: true 0044 0045 // system locale by default 0046 property string locale: "system" 0047 0048 signal start 0049 signal stop 0050 signal voiceError 0051 signal voiceDone 0052 0053 Component.onCompleted: { 0054 dialogActivityConfig.initialize() 0055 activity.start.connect(start) 0056 activity.stop.connect(stop) 0057 } 0058 0059 QtObject { 0060 id: items 0061 property Item activityPage: activity 0062 property int currentLevel: activity.currentLevel 0063 property alias trainModel: trainModel 0064 property GCAudio audioVoices: activity.audioVoices 0065 property GCSfx audioEffects: activity.audioEffects 0066 property alias parser: parser 0067 property alias questionItem: questionItem 0068 property alias repeatItem: repeatItem 0069 property alias score: score 0070 property alias bonus: bonus 0071 property alias locale: background.locale 0072 property bool keyNavigationMode: false 0073 property int lastSelectedIndex: -1 0074 property alias eventHandler: eventHandler 0075 property alias errorRectangle: errorRectangle 0076 property bool buttonsBlocked: false 0077 } 0078 0079 onVoiceError: { 0080 questionItem.visible = true; 0081 repeatItem.visible = false; 0082 } 0083 0084 onStart: { 0085 activity.audioVoices.done.connect(voiceDone); 0086 activity.audioVoices.error.connect(voiceError); 0087 Activity.start(items, mode); 0088 eventHandler.forceActiveFocus(); 0089 } 0090 0091 onStop: Activity.stop() 0092 0093 Item { 0094 id: eventHandler 0095 focus: true 0096 Keys.enabled: !items.buttonsBlocked && !dialogActivityConfig.visible 0097 Keys.onPressed: { 0098 if(event.key === Qt.Key_Tab) { 0099 activity.audioVoices.clearQueue(); 0100 activity.audioVoices.stop(); 0101 Activity.playLetter(Activity.currentLetter); 0102 } else { 0103 background.handleKeys(event); 0104 } 0105 } 0106 } 0107 0108 DialogChooseLevel { 0109 id: dialogActivityConfig 0110 currentActivity: activity.activityInfo 0111 onClose: { 0112 home(); 0113 eventHandler.forceActiveFocus(); 0114 } 0115 onSaveData: { 0116 levelFolder = dialogActivityConfig.chosenLevels; 0117 currentActivity.currentLevels = dialogActivityConfig.chosenLevels; 0118 ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels); 0119 } 0120 onLoadData: { 0121 if(activityData && activityData["locale"]) { 0122 background.locale = Core.resolveLocale(activityData["locale"]); 0123 } 0124 else { 0125 background.locale = Core.resolveLocale(background.locale); 0126 } 0127 } 0128 onStartActivity: { 0129 background.stop(); 0130 background.start(); 0131 eventHandler.forceActiveFocus(); 0132 } 0133 } 0134 0135 DialogHelp { 0136 id: dialogHelpLeftRight 0137 onClose: home() 0138 } 0139 0140 Bar { 0141 id: bar 0142 level: items.currentLevel + 1 0143 content: BarEnumContent { value: help | home | level | activityConfig } 0144 onHelpClicked: { 0145 displayDialog(dialogHelpLeftRight) 0146 } 0147 onPreviousLevelClicked: Activity.previousLevel() 0148 onNextLevelClicked: Activity.nextLevel() 0149 onHomeClicked: home() 0150 onActivityConfigClicked: { 0151 displayDialog(dialogActivityConfig) 0152 } 0153 } 0154 0155 Score { 0156 id: score 0157 anchors.top: parent.top 0158 anchors.topMargin: 10 * ApplicationInfo.ratio 0159 anchors.left: parent.left 0160 anchors.leftMargin: 10 * ApplicationInfo.ratio 0161 anchors.bottom: undefined 0162 anchors.right: undefined 0163 onStop: Activity.nextSubLevel() 0164 } 0165 0166 Bonus { 0167 id: bonus 0168 Component.onCompleted: win.connect(Activity.nextLevel) 0169 } 0170 0171 BarButton { 0172 id: repeatItem 0173 source: "qrc:/gcompris/src/core/resource/bar_repeat.svg"; 0174 sourceSize.width: 80 * ApplicationInfo.ratio 0175 anchors { 0176 top: parent.top 0177 right: parent.right 0178 margins: 10 0179 } 0180 onClicked: { 0181 if(!activity.audioVoices.isPlaying()) { 0182 Activity.playLetter(Activity.currentLetter); 0183 } 0184 } 0185 } 0186 0187 Image { 0188 id: railway 0189 source: Activity.url + "railway.svg" 0190 fillMode: Image.PreserveAspectCrop 0191 anchors.bottom: bar.top 0192 anchors.left: parent.left 0193 anchors.right: parent.right 0194 sourceSize.width: width 0195 sourceSize.height: height 0196 anchors.bottomMargin: 13 * ApplicationInfo.ratio 0197 } 0198 0199 Rectangle { 0200 id: questionItem 0201 anchors.fill: repeatItem 0202 border.color: "#FFFFFF" 0203 border.width: 2 0204 color: "#2881C3" 0205 radius: 10 0206 visible: false 0207 0208 property alias text: questionText.text 0209 0210 GCText { 0211 id: questionText 0212 anchors.centerIn: parent 0213 width: repeatItem.width 0214 height: repeatItem.height 0215 horizontalAlignment: Text.AlignHCenter 0216 verticalAlignment: Text.AlignVCenter 0217 z:11 0218 text: "" 0219 fontSizeMode: Text.Fit 0220 minimumPointSize: 10 0221 fontSize: width > 0 ? width : 128 0222 font.bold: true 0223 color: "white" 0224 } 0225 } 0226 0227 ListModel { 0228 id: trainModel 0229 } 0230 0231 //always calculate layout for a maximum of 24 letters per level 0232 //adding 1 extra to px and py to include one more item (the engine) in the calculation 0233 property int itemWidth: Core.fitItems(wholeTrainArea.width, wholeTrainArea.height, 24, 1) 0234 0235 Image { 0236 id: engine 0237 source: Activity.url + "engine.svg" 0238 anchors.bottom: railway.bottom 0239 anchors.left: railway.left 0240 anchors.leftMargin: 10 * ApplicationInfo.ratio 0241 anchors.bottomMargin: 5 * ApplicationInfo.ratio 0242 sourceSize.width: itemWidth 0243 sourceSize.height: itemWidth 0244 fillMode: Image.PreserveAspectFit 0245 } 0246 0247 Image { 0248 id: smoke 0249 source: Activity.url + "smoke.svg" 0250 anchors.bottom: engine.top 0251 anchors.left: railway.left 0252 anchors.leftMargin: 10 * ApplicationInfo.ratio 0253 anchors.bottomMargin: 5 * ApplicationInfo.ratio 0254 sourceSize.width: engine.width 0255 fillMode: Image.PreserveAspectFit 0256 } 0257 0258 Item { 0259 id: wholeTrainArea 0260 anchors.bottom: bar.top 0261 anchors.left: background.left 0262 anchors.right: background.right 0263 anchors.top: repeatItem.bottom 0264 anchors.leftMargin: 10 * ApplicationInfo.ratio 0265 anchors.bottomMargin: 5 * ApplicationInfo.ratio 0266 } 0267 0268 GridView { 0269 id: train 0270 anchors.bottom: engine.bottom 0271 anchors.top: wholeTrainArea.top 0272 anchors.right: wholeTrainArea.right 0273 anchors.left: engine.right 0274 cellWidth: itemWidth 0275 cellHeight: itemWidth 0276 clip: false 0277 interactive: false 0278 verticalLayoutDirection: GridView.BottomToTop 0279 layoutDirection: Qt.LeftToRight 0280 keyNavigationWraps: true 0281 currentIndex: -1 0282 0283 model: trainModel 0284 delegate: Carriage { 0285 width: train.cellWidth 0286 height: train.cellHeight 0287 nbCarriage: train.width / train.cellWidth - 1 0288 clickEnabled: items.buttonsBlocked ? false : (activity.audioVoices.playbackState == 1 ? false : true) 0289 isSelected: train.currentIndex === index 0290 } 0291 } 0292 0293 ErrorRectangle { 0294 id: errorRectangle 0295 z: 20 0296 anchors.centerIn: parent 0297 width: 2 0298 height: 2 0299 imageSize: train.cellWidth * 0.75 0300 function releaseControls() { 0301 items.buttonsBlocked = false; 0302 } 0303 } 0304 0305 function moveErrorRectangle(clickedItem) { 0306 errorRectangle.parent = clickedItem 0307 errorRectangle.startAnimation() 0308 items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/crash.wav"); 0309 } 0310 0311 function handleKeys(event) { 0312 if(!items.keyNavigationMode) { 0313 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav'); 0314 items.keyNavigationMode = true; 0315 if(items.lastSelectedIndex > 0 && items.lastSelectedIndex < trainModel.count) 0316 train.currentIndex = items.lastSelectedIndex; 0317 else 0318 train.currentIndex = 0; 0319 } else if(event.key === Qt.Key_Right) { 0320 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav'); 0321 train.moveCurrentIndexRight(); 0322 } else if(event.key === Qt.Key_Left) { 0323 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav'); 0324 train.moveCurrentIndexLeft(); 0325 } else if(event.key === Qt.Key_Up) { 0326 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav'); 0327 train.moveCurrentIndexUp(); 0328 } else if(event.key === Qt.Key_Down) { 0329 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav'); 0330 train.moveCurrentIndexDown(); 0331 } else if(event.key === Qt.Key_Space && activity.audioVoices.playbackState != 1) { 0332 items.buttonsBlocked = true; 0333 if(Activity.checkAnswer(train.currentIndex)) { 0334 train.currentItem.successAnimation.restart(); 0335 train.currentItem.particle.burst(30); 0336 } else { 0337 moveErrorRectangle(train.currentItem); 0338 } 0339 } 0340 } 0341 0342 JsonParser { 0343 id: parser 0344 onError: console.error("Click_on_letter: Error parsing JSON: " + msg); 0345 } 0346 0347 } 0348 }