Warning, /education/gcompris/src/activities/colors/FindIt.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - FindIt.qml
0002  *
0003  * SPDX-FileCopyrightText: 2015 Bruno Coudoin <bruno.coudoin@gcompris.net>
0004  *
0005  * Authors:
0006  *   Pascal Georges <pascal.georges1@free.fr> (GTK+ version)
0007  *   Bruno Coudoin <bruno.coudoin@gcompris.net> (Qt Quick port)
0008  *   Timothée Giet <animtim@gmail.com> (refactoring and various improvements)
0009  *
0010  *   SPDX-License-Identifier: GPL-3.0-or-later
0011  */
0012 
0013 import QtQuick 2.12
0014 import QtGraphicalEffects 1.0
0015 import GCompris 1.0
0016 
0017 import "../../core"
0018 import "findit.js" as Activity
0019 import "qrc:/gcompris/src/core/core.js" as Core
0020 
0021 ActivityBase {
0022     id: activity
0023     focus: true
0024 
0025     property var dataset
0026     property string backgroundImg
0027 
0028     property string mode: ""
0029 
0030     onStart: {
0031         focus = true;
0032     }
0033 
0034     pageComponent: Image {
0035         id: background
0036         focus: true
0037         fillMode: Image.PreserveAspectCrop
0038         sourceSize.width: width
0039         sourceSize.height: height
0040         source: backgroundImg
0041 
0042         property bool keyboardMode: false
0043         // if audio is disabled, we display a dialog to tell users this activity requires audio anyway
0044         property bool audioDisabled: false
0045 
0046         signal start
0047         signal stop
0048 
0049         Component.onCompleted: {
0050             activity.start.connect(start)
0051             activity.stop.connect(stop)
0052         }
0053         QtObject {
0054             id: items
0055             property Item activityPage: activity
0056             property alias background: background
0057             property int currentLevel: activity.currentLevel
0058             property alias bonus: bonus
0059             property alias containerModel: containerModel
0060             property alias initAnim: initAnim
0061             property alias nextAnim: nextAnim
0062             property alias fadeOutAnim: fadeOutAnim
0063             // On startup we want to queue the first sound but not after
0064             property bool firstQuestion: true
0065             property bool audioOk: false
0066             property alias score: score
0067             property bool objectSelected: true
0068             // we need to know the number of objects to calculate itemWidth before populating the container
0069             property int objectCount: 1
0070             // we need to copy tempModel to containerModel only once and only after all the rest is initialized
0071             property bool modelCopied: false
0072         }
0073         onStart: {
0074             if((!ApplicationSettings.isAudioVoicesEnabled || !ApplicationSettings.isAudioEffectsEnabled) && activity.isMusicalActivity) {
0075                 background.audioDisabled = true;
0076             } else {
0077                 Activity.start(items, dataset, mode);
0078             }
0079         }
0080         onStop: Activity.stop()
0081 
0082         Keys.onPressed: {
0083             if(event.key === Qt.Key_Space) {
0084                 container.currentItem.select()
0085             }
0086         }
0087         Keys.onReleased: {
0088             keyboardMode = true
0089             event.accepted = false
0090         }
0091         Keys.onEnterPressed: container.currentItem.select();
0092         Keys.onReturnPressed: container.currentItem.select();
0093         Keys.onRightPressed: container.moveCurrentIndexRight();
0094         Keys.onLeftPressed: container.moveCurrentIndexLeft();
0095         Keys.onDownPressed: container.moveCurrentIndexDown();
0096         Keys.onUpPressed: container.moveCurrentIndexUp();
0097         Keys.onTabPressed: if(repeatItem.visible) repeatItem.clicked();
0098 
0099         ListModel {
0100             id: containerModel
0101         }
0102 
0103         Rectangle {
0104             id: questionItem
0105             anchors.top: parent.top
0106             anchors.topMargin: 5 * ApplicationInfo.ratio
0107             anchors.horizontalCenter: parent.horizontalCenter
0108             width: questionText.contentWidth + 20 * ApplicationInfo.ratio
0109             height: Math.max(10 * ApplicationInfo.ratio, questionText.contentHeight + 5 * ApplicationInfo.ratio)
0110             radius: 5 * ApplicationInfo.ratio
0111             color: "#E2E2E2"
0112             border.color: "#373737"
0113             border.width: 2 * ApplicationInfo.ratio
0114             opacity: 0.01
0115 
0116             function initQuestion() {
0117                 questionText.text = Activity.getCurrentTextQuestion()
0118                 if(Activity.getCurrentAudioQuestion()) {
0119                     if(items.firstQuestion)
0120                         items.audioOk = activity.audioVoices.append(Activity.getCurrentAudioQuestion())
0121                     else {
0122                         activity.audioVoices.clearQueue()
0123                         items.audioOk = activity.audioVoices.play(Activity.getCurrentAudioQuestion())
0124                     }
0125                     items.firstQuestion = false
0126                 }
0127             }
0128 
0129             // initialization sequence for first question of first level
0130             SequentialAnimation {
0131                 id: initAnim
0132                 ScriptAction { script: questionItem.initQuestion() }
0133                 PauseAnimation { duration: 50 }
0134                 ScriptAction { script: if(!items.modelCopied)
0135                                             Activity.tempModelToContainer()
0136                 }
0137                 NumberAnimation { target: questionItem; property: "opacity"; to: 1; duration: 300 }
0138             }
0139 
0140             // fade-out anim only before bonus start
0141             NumberAnimation { id: fadeOutAnim; target: questionItem; property: "opacity"; to: 0.01; duration: 300 }
0142 
0143             // fade-out + init sequence after first question of a level
0144             SequentialAnimation {
0145                 id: nextAnim
0146                 NumberAnimation { target: questionItem; property: "opacity"; to: 0.01; duration: 300 }
0147                 ScriptAction { script: initAnim.restart() }
0148             }
0149 
0150             GCText {
0151                 id: questionText
0152                 anchors.centerIn: parent
0153                 fontSize: largeSize
0154                 width: background.width * 0.9
0155                 horizontalAlignment: Text.AlignHCenter
0156                 wrapMode: Text.WordWrap
0157                 font.weight: Font.DemiBold
0158                 color: "#373737"
0159             }
0160         }
0161 
0162         GridView {
0163             id: container
0164             model: containerModel
0165             anchors.top: questionItem.bottom
0166             anchors.topMargin: 10 * ApplicationInfo.ratio
0167             anchors.bottom: score.top
0168             anchors.horizontalCenter: background.horizontalCenter
0169             width: background.width - score.width * 2
0170             interactive: false
0171             cellWidth: itemWidth
0172             cellHeight: itemWidth
0173             keyNavigationWraps: true
0174 
0175             property int itemWidth: Core.fitItems(container.width, container.height, items.objectCount)
0176 
0177             delegate: ColorItem {
0178                 audioVoices: activity.audioVoices
0179                 source: model.image
0180                 audioSrc: model.audio ? model.audio : ""
0181                 question: model.text
0182                 sourceSize.height: container.itemWidth * 0.9
0183                 sourceSize.width: container.itemWidth * 0.9
0184             }
0185             add: Transition {
0186                 PathAnimation {
0187                     path: Path {
0188                         PathCurve { x: background.width / 3}
0189                         PathCurve { y: background.height / 3}
0190                         PathCurve {}
0191                     }
0192                     easing.type: Easing.InOutQuad
0193                     duration: 2000
0194                 }
0195             }
0196             highlight: Rectangle {
0197                 width: container.cellWidth
0198                 height: container.cellHeight
0199                 color:  "#AAFFFFFF"
0200                 border.width: 3
0201                 border.color: "black"
0202                 visible: background.keyboardMode
0203                 Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } }
0204                 Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } }
0205             }
0206         }
0207 
0208         DialogHelp {
0209             id: dialogHelp
0210             onClose: home()
0211         }
0212 
0213         Bar {
0214             id: bar
0215             level: items.currentLevel + 1
0216             content: BarEnumContent { value: help | home | level }
0217             onHelpClicked: {
0218                 displayDialog(dialogHelp)
0219             }
0220             onPreviousLevelClicked: Activity.previousLevel()
0221             onNextLevelClicked: Activity.nextLevel()
0222             onHomeClicked: activity.home()
0223         }
0224 
0225         BarButton {
0226             id: repeatItem
0227             source: "qrc:/gcompris/src/core/resource/bar_repeat.svg";
0228             sourceSize.height: visible ? 80 * ApplicationInfo.ratio : 1
0229             z: bar.z + 1
0230             visible: items.audioOk
0231             anchors {
0232                 bottom: bar.top
0233                 right: parent.right
0234                 margins: 10 * ApplicationInfo.ratio
0235             }
0236             onClicked: if (!activity.audioVoices.isPlaying())
0237                            questionItem.initQuestion()
0238         }
0239 
0240         Score {
0241             id: score
0242             anchors.bottom: bar.top
0243             anchors.right: bar.right
0244             anchors.left: parent.left
0245             anchors.bottomMargin: 10 * ApplicationInfo.ratio
0246             anchors.leftMargin: 10 * ApplicationInfo.ratio
0247             anchors.rightMargin: 0
0248         }
0249 
0250         Bonus {
0251             id: bonus
0252             interval: 2000
0253             Component.onCompleted: win.connect(Activity.nextLevel)
0254         }
0255 
0256         Loader {
0257             id: audioNeededDialog
0258             sourceComponent: GCDialog {
0259                 parent: activity
0260                 isDestructible: false
0261                 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.")
0262                 button1Text: qsTr("Quit")
0263                 button2Text: qsTr("Continue")
0264                 onButton1Hit: activity.home();
0265                 onClose: {
0266                     background.audioDisabled = false;
0267                     Activity.start(items, dataset, mode);
0268                 }
0269             }
0270             anchors.fill: parent
0271             focus: true
0272             active: background.audioDisabled
0273             onStatusChanged: if (status == Loader.Ready) item.start()
0274         }
0275     }
0276 
0277 }