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

0001 /* GCompris - GrammarAnalysis.qml
0002  *
0003  * Copyright (C) 2022-2023 Bruno ANSELME <be.root@free.fr>
0004  *
0005  * Authors:
0006  *   Bruno ANSELME <be.root@free.fr> (Qt Quick native)
0007  *   Timothée Giet <animtim@gmail.com> (Graphics and layout refactoring)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 import QtQuick 2.12
0012 import QtQuick.Controls 2.12
0013 import GCompris 1.0
0014 
0015 import "../../core"
0016 import "grammar_analysis.js" as Activity
0017 import "qrc:/gcompris/src/core/core.js" as Core
0018 
0019 ActivityBase {
0020     id: activity
0021 
0022     property string grammarMode: "_analysis"            // Modified for grammar_classes
0023     readonly property bool translationMode: false       // Set this value to true to activate translator's mode
0024 
0025     onStart: focus = true
0026     onStop: {}
0027 
0028     pageComponent: Image {
0029         id: background
0030         source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg"
0031         sourceSize.width: width
0032         sourceSize.height: height
0033         fillMode: Image.PreserveAspectCrop
0034         anchors.fill: parent
0035         signal start
0036         signal stop
0037 
0038         // system locale by default
0039         property string locale: "system"
0040         property int baseMargins: 10 * ApplicationInfo.ratio
0041         property int baseRadius: 2 * ApplicationInfo.ratio
0042         property string selectionColor: "#A1CBD9"
0043 
0044         Component.onCompleted: {
0045             dialogActivityConfig.initialize()
0046             activity.start.connect(start)
0047             activity.stop.connect(stop)
0048         }
0049 
0050         // Add here the QML items you need to access in javascript
0051         QtObject {
0052             id: items
0053             property Item activityPage: activity
0054             property alias background: background
0055             property int currentLevel: activity.currentLevel
0056             property alias bonus: bonus
0057             property alias locale: background.locale
0058             property alias score: score
0059             property GCSfx audioEffects: activity.audioEffects
0060             property bool buttonsBlocked: false
0061             // Qml models
0062             property alias syntaxModel: syntaxModel
0063             property alias datasetModel: datasetModel
0064             property alias goalModel: goalModel
0065             property alias answerModel: answerModel
0066             // Qml main items
0067             property alias wordsFlow: wordsFlow
0068             property alias rowAnswer: rowAnswer
0069             property alias gridGoalTokens: gridGoalTokens
0070             property alias errorRectangle: errorRectangle
0071             // Activity parameters
0072             property int selectedClass: 0
0073             property int selectedBox: 0
0074             property int currentExercise: 0
0075             property alias objective: objective
0076             property bool keyboardNavigation: false
0077             property bool keysOnTokens: true                // True when focus is on grammatical tokens else if focus is on words
0078             property var boxIndexes: []                     // Array of pairs <word number>-<subclass number (box)>
0079             property alias okButton: okButton
0080             property alias file: file
0081             property alias jsonParser: jsonParser
0082             property alias errors: errors
0083             //--- Debug properties
0084             property bool debugActive: false
0085             property alias inspector: inspector
0086             property alias phrase: phrase
0087             property alias response: response
0088             property string goalStr: ""
0089             property string translationFile: ""             // Display translation file's basename
0090             //--- End of debug properties
0091         }
0092 
0093         onStart: { Activity.start(items, grammarMode, translationMode) }
0094         onStop: { Activity.stop() }
0095 
0096         File {
0097             id: file
0098             onError: console.error("File error: " + msg)
0099         }
0100 
0101         JsonParser {
0102             id: jsonParser
0103             onError: errors.text = msg.replace(/invalid\:/,'invalid<br>')
0104         }
0105 
0106         ListModel { id: syntaxModel }
0107         ListModel { id: goalModel }
0108         ListModel { id: answerModel }
0109         ListModel {
0110             id: datasetModel
0111             function randPosition() {                       // choose a random position
0112                 return (Math.floor(Math.random() * count))
0113             }
0114             function shuffleModel() {                       // shuffle exercises
0115                 for (var i = 0 ; i < count; i++) {
0116                     move(randPosition(), randPosition(), 1)
0117                 }
0118             }
0119         }
0120 
0121         // Tutorial section
0122         Image {
0123             id: tutorialScreen
0124             source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg"
0125             anchors.fill: parent
0126             sourceSize.width: width
0127             sourceSize.height: height
0128             fillMode: Image.PreserveAspectCrop
0129             visible: true
0130             Tutorial {
0131                 id: tutorialSection
0132                 useImage: false
0133                 tutorialDetails: Activity.tutorialInstructions[grammarMode]
0134                 onSkipPressed: {
0135                     Activity.initLevel()
0136                     tutorialScreen.visible = false
0137                 }
0138             }
0139         }
0140 
0141         Column { // invisible column to get longest word from the class names
0142             id: tokenTextSizeRef
0143             visible: false
0144             width: childrenRect.width
0145             Repeater {
0146                 model: goalModel
0147                 delegate: GCText {
0148                     fontSize: tinySize
0149                     text: wordClass
0150                 }
0151             }
0152         }
0153 
0154         // Main section
0155         Item {
0156             id: mainArea
0157             anchors.top: parent.top
0158             anchors.bottom: scoreButtonContainer.top
0159             anchors.left: parent.left
0160             anchors.right: parent.right
0161             anchors.margins: background.baseMargins
0162             visible: !tutorialScreen.visible
0163             Column {
0164                 anchors.top: parent.top
0165                 anchors.horizontalCenter: parent.horizontalCenter
0166                 width: parent.width
0167                 height: parent.height
0168                 spacing: background.baseMargins
0169                 Rectangle {
0170                     id: objectiveContainer
0171                     width: objective.paintedWidth + background.baseMargins * 2
0172                     height: objective.paintedHeight + background.baseMargins
0173                     color: "#80FFFFFF"
0174                     radius: background.baseRadius
0175                     anchors.horizontalCenter: parent.horizontalCenter
0176                     GCText {        // Exercise's objective
0177                         id: objective
0178                         fontSize: regularSize
0179                         fontSizeMode: Text.Fit
0180                         width: mainArea.width - background.baseMargins * 2
0181                         height: mainArea.height * 0.2 - background.baseMargins
0182                         horizontalAlignment: Text.AlignHCenter
0183                         verticalAlignment: Text.AlignVCenter
0184                         anchors.horizontalCenter: parent.horizontalCenter
0185                         anchors.verticalCenter: parent.verticalCenter
0186                         wrapMode: Text.WordWrap
0187                     }
0188                 }
0189                 Rectangle {     // Display grammatical classes (goal)
0190                     id: goalTokensContainer
0191                     color: "#F0F0F0"
0192                     anchors.horizontalCenter: parent.horizontalCenter
0193                     width: gridGoalTokens.width + background.baseMargins
0194                     height: gridGoalTokens.height + background.baseMargins
0195                     radius: background.baseRadius
0196                     focus: true
0197                     z: 2
0198                     Rectangle {
0199                         z: -1
0200                         color: background.selectionColor
0201                         radius: background.baseRadius
0202                         visible: items.keyboardNavigation && items.keysOnTokens
0203                         anchors.centerIn: parent
0204                         width: parent.width + background.baseMargins
0205                         height: parent.height + background.baseMargins
0206                     }
0207                     Grid {
0208                         id: gridGoalTokens
0209                         anchors.centerIn: parent
0210                         columns: mainArea.width / tokenWidth
0211                         layoutDirection: (Core.isLeftToRightLocale(items.locale)) ?  Qt.LeftToRight : Qt.RightToLeft
0212 
0213                         property real tokenWidth: Math.max(75 * ApplicationInfo.ratio, tokenTextSizeRef.width)
0214                         property real tokenHeight: columns < goalModel.count ? 40 * ApplicationInfo.ratio : 60 * ApplicationInfo.ratio
0215 
0216                         Repeater {
0217                             model: goalModel
0218                             delegate: GrammarToken {
0219                                 width: gridGoalTokens.tokenWidth
0220                                 height: gridGoalTokens.tokenHeight
0221                                 classCode: code
0222                                 className: wordClass
0223                                 svgName: image
0224                             }
0225                         }
0226                     }
0227                 }
0228                 Item {
0229                     id: wordsArea
0230                     width: mainArea.width
0231                     height: mainArea.height - objectiveContainer.height - goalTokensContainer.height - background.baseMargins * 2
0232 
0233                     property real itemHeight: Math.min(40 * ApplicationInfo.ratio, height * 0.2)
0234                     property bool isSmallHeight: itemHeight < 30 * ApplicationInfo.ratio
0235 
0236                     Rectangle {     // Display sentence
0237                         color: "#F0F0F0"
0238                         width: parent.width
0239                         height: wordsFlow.height
0240                         radius: background.baseRadius
0241                         Rectangle {
0242                             z: -1
0243                             color: background.selectionColor
0244                             radius: background.baseRadius
0245                             visible: items.keyboardNavigation && !items.keysOnTokens
0246                             anchors.centerIn: parent
0247                             width: parent.width + background.baseMargins
0248                             height: parent.height + background.baseMargins
0249                         }
0250                         Flow {
0251                             id: wordsFlow
0252                             width: parent.width - background.baseMargins * 2
0253                             spacing: 0
0254                             leftPadding: background.baseMargins
0255                             rightPadding: background.baseMargins
0256                             anchors.verticalCenter: parent.verticalCenter
0257                             layoutDirection: (Core.isLeftToRightLocale(items.locale)) ?  Qt.LeftToRight : Qt.RightToLeft
0258                             Repeater {
0259                                 id: rowAnswer
0260                                 model: answerModel
0261                                 delegate: WordAndClass {
0262                                     expected: code
0263                                     wordText: word
0264                                     proposition: prop
0265                                     startPos: startCount
0266                                 }
0267                             }
0268                         }
0269                         ErrorRectangle {
0270                             id: errorRectangle
0271                             anchors.fill: parent
0272                             radius: parent.radius
0273                             imageSize: okButton.width
0274                             function releaseControls() { items.buttonsBlocked = false; }
0275                         }
0276                     }
0277                     GCText {        // Error text
0278                         id: errors
0279                         color: "red"
0280                         style: Text.Outline
0281                         styleColor: "white"
0282                         fontSize: tinySize
0283                         anchors.horizontalCenter:  parent.horizontalCenter
0284                     }
0285                 }
0286             }
0287             MouseArea {
0288                 // used to block all mouse input on activity interface execpt the OK button
0289                 anchors.fill: parent
0290                 enabled: items.buttonsBlocked
0291             }
0292         }
0293 
0294         DialogChooseLevel {
0295             id: dialogActivityConfig
0296             currentActivity: activity.activityInfo
0297 
0298             onSaveData: {
0299                 levelFolder = dialogActivityConfig.chosenLevels
0300                 currentActivity.currentLevels = dialogActivityConfig.chosenLevels
0301                 ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels)
0302             }
0303             onLoadData: {
0304                 if(activityData && activityData["locale"]) {
0305                     background.locale = Core.resolveLocale(activityData["locale"]);
0306                 }
0307                 else {
0308                     background.locale = Core.resolveLocale(background.locale);
0309                 }
0310             }
0311             onClose: {
0312                 home()
0313             }
0314             onStartActivity: {
0315                 background.start()
0316             }
0317         }
0318         DialogHelp {
0319             id: dialogHelp
0320             onClose: home()
0321         }
0322 
0323         Bar {
0324             id: bar
0325             level: items.currentLevel + 1
0326             content: BarEnumContent { value: tutorialScreen.visible ? help | home : help | home | level | activityConfig }
0327             onHelpClicked: displayDialog(dialogHelp)
0328             onActivityConfigClicked: displayDialog(dialogActivityConfig)
0329             onPreviousLevelClicked: Activity.previousLevel()
0330             onNextLevelClicked: Activity.nextLevel()
0331             onHomeClicked: activity.home()
0332         }
0333 
0334         Item {
0335             id: scoreButtonContainer
0336             visible: !tutorialScreen.visible
0337             width: score.width + background.baseMargins + okButton.width
0338             height: okButton.height
0339             anchors.horizontalCenter: parent.horizontalCenter
0340             anchors.bottom: background.bottom
0341             anchors.bottomMargin: 1.5 * bar.height
0342 
0343             BarButton {
0344                 id: okButton
0345                 source: "qrc:/gcompris/src/core/resource/bar_ok.svg"
0346                 width: 60 * ApplicationInfo.ratio
0347                 anchors.right: parent.right
0348                 anchors.bottom: parent.bottom
0349                 sourceSize.width: width
0350                 onClicked: Activity.checkResult()
0351                 mouseArea.enabled: !items.buttonsBlocked
0352             }
0353 
0354             Score {
0355                 id: score
0356                 numberOfSubLevels: items.datasetModel.count
0357                 currentSubLevel: items.currentExercise
0358                 anchors.left: parent.left
0359                 anchors.verticalCenter: parent.verticalCenter
0360                 anchors.margins: 0
0361                 anchors.bottom: undefined
0362                 anchors.top: undefined
0363                 anchors.right: undefined
0364                 visible: !tutorialScreen.visible
0365                 onStop: Activity.nextSubLevel()
0366             }
0367         }
0368 
0369         Bonus {
0370             id: bonus
0371             Component.onCompleted: win.connect(Activity.nextLevel)
0372         }
0373 
0374         Keys.onPressed: Activity.handleKeys(event)
0375 
0376         //--- Debugging zone.
0377         Text {
0378             id: hideDebug
0379             text: "Alt+Left and Alt+Right to change exercise\nCtrl+Alt+Return to flip debug informations"
0380             anchors.top: scoreButtonContainer.bottom
0381             anchors.right: parent.right
0382             visible: translationMode
0383         }
0384         Column {
0385             id: infoView
0386             anchors.bottom: scoreButtonContainer.bottom
0387             visible: items.debugActive
0388             spacing: 5
0389             Text {
0390                 width: 200
0391                 height: 80
0392                 text: "Activity: %1\nLocale: %2\nTranslation file: %3\nExercise: %4/%5\nGoal: %6".arg(activityInfo.title).arg(items.locale).arg(items.translationFile).arg(items.currentExercise + 1).arg(datasetModel.count).arg(items.goalStr)
0393             }
0394             Text {
0395                 id: phrase
0396                 width: 200
0397                 height: 16
0398             }
0399             Text {
0400                 id: response
0401                 width: 200
0402                 height: 16
0403             }
0404         }
0405 
0406         Rectangle {
0407             id: inspector
0408             property alias message: msg.text
0409             property bool shown: false
0410             anchors.top: parent.top
0411             anchors.left: parent.left
0412             width: shown ? msg.contentWidth + 10 : 70
0413             height: shown ? msg.contentHeight + 4 : 18
0414             color: "white"
0415             opacity: 0.5
0416             radius: 5
0417             visible: items.debugActive
0418             Text {
0419                 id: msg
0420                 anchors.fill: parent
0421                 text: "Debug area"
0422                 clip: true
0423             }
0424             MouseArea {
0425                 anchors.fill: parent
0426                 hoverEnabled: true
0427                 onClicked: { parent.shown = !parent.shown }
0428                 onEntered: { inspector.opacity = 1.0 }
0429                 onExited: { inspector.opacity = 0.5 }
0430             }
0431         }
0432         //--- End of debugging zone.
0433     }
0434 }