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 }