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 }