Warning, /education/gcompris/src/activities/mosaic/Mosaic.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - mosaic.qml 0002 * 0003 * SPDX-FileCopyrightText: 2014 Bruno Coudoin <bruno.coudoin@gcompris.net> 0004 * 0005 * Authors: 0006 * Clement coudoin <clement.coudoin@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 "mosaic.js" as Activity 0016 import "qrc:/gcompris/src/core/core.js" as Core 0017 0018 ActivityBase { 0019 id: activity 0020 0021 onStart: focus = true 0022 onStop: {} 0023 0024 pageComponent: Image { 0025 id: background 0026 source: Activity.url + "background.svg" 0027 sourceSize.width: width 0028 sourceSize.height: height 0029 fillMode: Image.PreserveAspectCrop 0030 anchors.fill: parent 0031 signal start 0032 signal stop 0033 0034 property bool keyboardMode: false 0035 property var areaWithKeyboardFocus: selector 0036 0037 Component.onCompleted: { 0038 dialogActivityConfig.initialize() 0039 activity.start.connect(start) 0040 activity.stop.connect(stop) 0041 } 0042 0043 // Add here the QML items you need to access in javascript 0044 QtObject { 0045 id: items 0046 property Item main: activity.main 0047 property GCSfx audioEffects: activity.audioEffects 0048 property alias question: question 0049 property alias answer: answer 0050 property alias selector: selector 0051 property alias background: background 0052 property int currentLevel: activity.currentLevel 0053 property alias bonus: bonus 0054 property string selectedItem 0055 readonly property var levels: activity.datasetLoader.data 0056 property int nbItems 0057 property int questionLayoutColumns 0058 property int questionLayoutRows 0059 property string modelDisplayLayout 0060 } 0061 0062 onStart: { Activity.start(items) } 0063 onStop: { Activity.stop() } 0064 0065 Keys.onLeftPressed: { 0066 keyboardMode = true 0067 areaWithKeyboardFocus.moveCurrentIndexLeft() 0068 } 0069 0070 Keys.onRightPressed: { 0071 keyboardMode = true 0072 areaWithKeyboardFocus.moveCurrentIndexRight() 0073 } 0074 0075 Keys.onUpPressed: { 0076 keyboardMode = true 0077 areaWithKeyboardFocus.moveCurrentIndexUp() 0078 } 0079 0080 Keys.onDownPressed: { 0081 keyboardMode = true 0082 areaWithKeyboardFocus.moveCurrentIndexDown() 0083 } 0084 0085 Keys.onEnterPressed: { 0086 selectCell() 0087 } 0088 0089 Keys.onSpacePressed: { 0090 selectCell() 0091 } 0092 0093 Keys.onReturnPressed: { 0094 selectCell() 0095 } 0096 0097 Keys.onTabPressed: { 0098 keyboardMode = true 0099 areaWithKeyboardFocus.changeAreaWithKeyboardFocus() 0100 } 0101 0102 function selectCell() { 0103 keyboardMode = true 0104 areaWithKeyboardFocus.selectCurrentCell(areaWithKeyboardFocus.currentItem) 0105 } 0106 0107 Rectangle { 0108 id: mainArea 0109 anchors.top: background.top 0110 anchors.bottom: bar.top 0111 anchors.left: background.left 0112 anchors.right: background.right 0113 color: "#00FFFFFF" 0114 0115 property int nbItems: 24 0116 property bool horizontal: background.width >= background.height 0117 property bool smallQuestionMode: items.modelDisplayLayout === "smaller" 0118 property int nbColumns: items.questionLayoutColumns 0119 property int nbLines: items.questionLayoutRows 0120 property int layoutMargin: Math.floor(10 * ApplicationInfo.ratio) 0121 property int itemsMargin: Math.floor(5 * ApplicationInfo.ratio) 0122 0123 states: [ 0124 State { 0125 name: "horizontal" 0126 when: mainArea.horizontal 0127 AnchorChanges { 0128 target: questionRectangle 0129 anchors.top: parent.top 0130 anchors.left: parent.left 0131 anchors.horizontalCenter: undefined 0132 } 0133 PropertyChanges { 0134 target: answerRectangle 0135 height: mainArea.height * 0.66 - mainArea.layoutMargin * 2 0136 width: mainArea.width * 0.5 - mainArea.layoutMargin * 1.5 0137 } 0138 AnchorChanges { 0139 target: answerRectangle 0140 anchors.top: parent.top 0141 anchors.left: questionRectangle.right 0142 } 0143 }, 0144 State { 0145 name: "vertical" 0146 when: !mainArea.horizontal 0147 AnchorChanges { 0148 target: questionRectangle 0149 anchors.top: parent.top 0150 anchors.left: parent.left 0151 anchors.horizontalCenter: undefined 0152 } 0153 PropertyChanges { 0154 target: answerRectangle 0155 height: mainArea.height / 3 - mainArea.layoutMargin * 2 0156 width: mainArea.width - mainArea.layoutMargin * 2 0157 } 0158 AnchorChanges { 0159 target: answerRectangle 0160 anchors.top: questionRectangle.bottom 0161 anchors.left: parent.left 0162 } 0163 } 0164 ] 0165 0166 // === The Question Area === 0167 Rectangle { 0168 id: questionRectangle 0169 color: "#00FFFFFF" 0170 height: answerRectangle.height 0171 width: answerRectangle.width 0172 anchors.top: mainArea.top 0173 anchors.left: mainArea.left 0174 anchors.topMargin: mainArea.layoutMargin 0175 anchors.leftMargin: mainArea.layoutMargin 0176 Rectangle { 0177 id: questionRectangleContent 0178 anchors.centerIn: parent 0179 color: "#55333333" 0180 border.color: "black" 0181 border.width: 2 0182 radius: 5 0183 0184 states: [ 0185 State { 0186 name: "smallQuestion" 0187 when: mainArea.smallQuestionMode 0188 PropertyChanges { 0189 target: questionRectangleContent 0190 height: answerRectangle.height * 0.7 0191 width: answerRectangle.width * 0.7 0192 } 0193 }, 0194 State { 0195 name: "normalQuestion" 0196 when: !mainArea.smallQuestionMode 0197 PropertyChanges { 0198 target: questionRectangleContent 0199 height: answerRectangle.height 0200 width: answerRectangle.width 0201 } 0202 } 0203 ] 0204 0205 GridView { 0206 id: question 0207 width: cellWidth * mainArea.nbColumns 0208 height: cellHeight * mainArea.nbLines 0209 anchors.centerIn: parent 0210 cellHeight: cellWidth 0211 cellWidth: Math.floor(Math.min((parent.width - mainArea.itemsMargin) / mainArea.nbColumns, (parent.height - mainArea.itemsMargin) / mainArea.nbLines)) 0212 interactive: false 0213 keyNavigationWraps: true 0214 delegate: Item { 0215 width: question.cellWidth 0216 height: question.cellHeight 0217 Image { 0218 id: imageQuestionId 0219 source: Activity.url + modelData 0220 fillMode: Image.PreserveAspectFit 0221 width: question.cellWidth - mainArea.itemsMargin 0222 height: width 0223 sourceSize.width: width 0224 sourceSize.height: width 0225 anchors.centerIn: parent 0226 } 0227 } 0228 } 0229 } 0230 } 0231 0232 // === The Answer Area === 0233 Rectangle { 0234 id: answerRectangle 0235 height: mainArea.height * 0.33 - mainArea.layoutMargin * 2 0236 width: mainArea.width - mainArea.layoutMargin * 2 0237 anchors.top: questionRectangle.bottom 0238 anchors.left: mainArea.left 0239 anchors.topMargin: mainArea.layoutMargin 0240 anchors.leftMargin: mainArea.layoutMargin 0241 color: "#55333333" 0242 border.color: "black" 0243 border.width: 2 0244 radius: 5 0245 0246 GridView { 0247 id: answer 0248 width: cellWidth * mainArea.nbColumns 0249 height: cellHeight * mainArea.nbLines 0250 anchors.centerIn: parent 0251 cellHeight: cellWidth 0252 cellWidth: Math.floor(Math.min((parent.width - mainArea.itemsMargin) / mainArea.nbColumns, (parent.height - mainArea.itemsMargin) / mainArea.nbLines)) 0253 interactive: false 0254 keyNavigationWraps: true 0255 highlightFollowsCurrentItem: true 0256 highlight: Rectangle { 0257 color: "red" 0258 border.width: 3 0259 border.color: "black" 0260 opacity: 0.6 0261 visible: background.keyboardMode && (background.areaWithKeyboardFocus === answer) 0262 Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } } 0263 Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } 0264 } 0265 0266 // If the image was directly used as a delegate (without containing it in the item), the highlight element would have been be hard to notice as it would get completely hidden by the image due to the same sizes. 0267 delegate: Item { 0268 id: cellItem 0269 width: answer.cellWidth 0270 height: answer.cellHeight 0271 0272 readonly property int cellIndex: index 0273 0274 Image { 0275 id: imageAnswerId 0276 source: Activity.url + modelData 0277 fillMode: Image.PreserveAspectFit 0278 width: answer.cellWidth - mainArea.itemsMargin 0279 height: width 0280 sourceSize.width: width 0281 sourceSize.height: height 0282 anchors.centerIn: parent 0283 0284 MouseArea { 0285 anchors.fill: parent 0286 onClicked: answer.selectCurrentCell(cellItem) 0287 } 0288 } 0289 } 0290 function selectCurrentCell(selectedCell) { 0291 Activity.answerSelected(selectedCell.cellIndex) 0292 } 0293 0294 function changeAreaWithKeyboardFocus() { 0295 areaWithKeyboardFocus = selector 0296 } 0297 } 0298 } 0299 0300 // === The Selector === 0301 Rectangle { 0302 id: selectorRectangle 0303 height: mainArea.height * 0.33 - mainArea.layoutMargin * 2 0304 width: mainArea.width - mainArea.layoutMargin * 2 0305 anchors.top: answerRectangle.bottom 0306 anchors.left: mainArea.left 0307 anchors.topMargin: mainArea.layoutMargin 0308 anchors.leftMargin: mainArea.layoutMargin 0309 color: "#661111AA" 0310 border.color: "black" 0311 border.width: 2 0312 radius: 5 0313 property int selectorItemSize: Core.fitItems(selectorRectangle.width - mainArea.itemsMargin, selectorRectangle.height - mainArea.itemsMargin, selector.count) 0314 0315 GridView { 0316 id: selector 0317 width: parent.width 0318 height: parent.height 0319 anchors.centerIn: parent 0320 cellHeight: selectorRectangle.selectorItemSize 0321 cellWidth: selectorRectangle.selectorItemSize 0322 interactive: false 0323 keyNavigationWraps: true 0324 highlightFollowsCurrentItem: true 0325 highlight: Rectangle { 0326 color: "red" 0327 border.width: 3 0328 border.color: "black" 0329 opacity: 0.6 0330 visible: background.keyboardMode && (background.areaWithKeyboardFocus === selector) 0331 Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } } 0332 Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } 0333 } 0334 delegate: Item { 0335 id: selectorItem 0336 width: selector.cellWidth 0337 height: width 0338 Image { 0339 id: imageId 0340 source: Activity.url + modelData 0341 fillMode: Image.PreserveAspectFit 0342 width: selector.cellWidth - mainArea.itemsMargin 0343 height: width 0344 sourceSize.width: width 0345 sourceSize.height: height 0346 antialiasing: true 0347 anchors.centerIn: parent 0348 z: selectorItem.iAmSelected ? 10 : 1 0349 } 0350 0351 readonly property bool iAmSelected: items.selectedItem === modelData 0352 readonly property string imageName: modelData 0353 0354 states: [ 0355 State { 0356 name: "notclicked" 0357 when: !selectorItem.iAmSelected && !mouseArea.containsMouse 0358 PropertyChanges { 0359 target: imageId 0360 scale: 0.8 0361 } 0362 }, 0363 State { 0364 name: "clicked" 0365 when: mouseArea.pressed 0366 PropertyChanges { 0367 target: imageId 0368 scale: 0.7 0369 } 0370 }, 0371 State { 0372 name: "hover" 0373 when: mouseArea.containsMouse 0374 PropertyChanges { 0375 target: imageId 0376 scale: 1 0377 } 0378 }, 0379 State { 0380 name: "selected" 0381 when: selectorItem.iAmSelected 0382 PropertyChanges { 0383 target: imageId 0384 scale: 1 0385 } 0386 } 0387 ] 0388 0389 SequentialAnimation { 0390 id: anim 0391 running: selectorItem.iAmSelected 0392 loops: Animation.Infinite 0393 alwaysRunToEnd: true 0394 NumberAnimation { 0395 target: imageId 0396 property: "rotation" 0397 from: 0; to: 10 0398 duration: 200 0399 easing.type: Easing.OutQuad 0400 } 0401 NumberAnimation { 0402 target: imageId 0403 property: "rotation" 0404 from: 10; to: -10 0405 duration: 400 0406 easing.type: Easing.InOutQuad 0407 } 0408 NumberAnimation { 0409 target: imageId 0410 property: "rotation" 0411 from: -10; to: 0 0412 duration: 200 0413 easing.type: Easing.InQuad 0414 } 0415 } 0416 0417 Behavior on scale { NumberAnimation { duration: 70 } } 0418 MouseArea { 0419 id: mouseArea 0420 anchors.fill: imageId 0421 hoverEnabled: true 0422 onClicked: selector.selectCurrentCell(parent) 0423 } 0424 } 0425 0426 function selectCurrentCell(selectedCell) { 0427 items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/scroll.wav") 0428 items.selectedItem = selectedCell.imageName 0429 } 0430 0431 function changeAreaWithKeyboardFocus() { 0432 areaWithKeyboardFocus = answer 0433 } 0434 } 0435 } 0436 } 0437 0438 DialogChooseLevel { 0439 id: dialogActivityConfig 0440 currentActivity: activity.activityInfo 0441 0442 onSaveData: { 0443 levelFolder = dialogActivityConfig.chosenLevels 0444 currentActivity.currentLevels = dialogActivityConfig.chosenLevels 0445 ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels) 0446 // restart activity on saving 0447 background.start() 0448 } 0449 onClose: { 0450 home() 0451 } 0452 onStartActivity: { 0453 background.start() 0454 } 0455 } 0456 0457 DialogHelp { 0458 id: dialogHelp 0459 onClose: home() 0460 } 0461 0462 Bar { 0463 id: bar 0464 level: items.currentLevel + 1 0465 content: BarEnumContent { value: help | home | level | activityConfig} 0466 onHelpClicked: { 0467 displayDialog(dialogHelp) 0468 } 0469 onActivityConfigClicked: { 0470 displayDialog(dialogActivityConfig) 0471 } 0472 onPreviousLevelClicked: Activity.previousLevel() 0473 onNextLevelClicked: Activity.nextLevel() 0474 onHomeClicked: activity.home() 0475 } 0476 0477 Bonus { 0478 id: bonus 0479 Component.onCompleted: win.connect(Activity.nextLevel) 0480 } 0481 } 0482 }