Warning, /education/gcompris/src/activities/guess24/Guess24.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - guess24.qml 0002 * 0003 * SPDX-FileCopyrightText: 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 * References : 0012 * https://www.4nums.com/game/difficulties/ 0013 * https://www.4nums.com/solutions/allsolvables/ (2023-07-08 datas) 0014 * https://fr.y8.com/games/make_24 0015 */ 0016 import QtQuick 2.12 0017 import GCompris 1.0 0018 0019 import "../../core" 0020 import "qrc:/gcompris/src/core/core.js" as Core 0021 import "guess24.js" as Activity 0022 0023 ActivityBase { 0024 id: activity 0025 0026 onStart: focus = true 0027 onStop: {} 0028 0029 pageComponent: Image { 0030 id: background 0031 source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg" 0032 sourceSize.width: width 0033 sourceSize.height: height 0034 fillMode: Image.PreserveAspectCrop 0035 anchors.fill: parent 0036 signal start 0037 signal stop 0038 0039 property int baseMargins: 5 * ApplicationInfo.ratio 0040 property int baseRadius: 2 * ApplicationInfo.ratio 0041 property string baseColor: "#A1CBD9" 0042 property string selectionColor: "#4B9BB5" 0043 property int selectionWidth: 4 * ApplicationInfo.ratio 0044 0045 Component.onCompleted: { 0046 dialogActivityConfig.initialize() 0047 activity.start.connect(start) 0048 activity.stop.connect(stop) 0049 } 0050 0051 // Add here the QML items you need to access in javascript 0052 QtObject { 0053 id: items 0054 property Item main: activity.main 0055 property alias background: background 0056 property int currentLevel: activity.currentLevel 0057 property alias bonus: bonus 0058 property alias score: score 0059 property alias errorRectangle: errorRectangle 0060 property var levels: activity.datasetLoader.data 0061 property GCSfx audioEffects: activity.audioEffects 0062 property alias jsonParser: jsonParser 0063 property int currentValue: 0 0064 property int currentOperator: -1 0065 property int operatorsCount: 4 0066 property int subLevelCount: 0 0067 property bool keysOnValues: true // True when focus is on values false if focus is on operators 0068 property alias cardsModel: cardsModel 0069 property alias cardsBoard: cardsBoard 0070 property alias operators: operators 0071 property alias cancelButton: cancelButton 0072 property alias hintButton: hintButton 0073 property alias animationCard: animationCard 0074 property alias steps: steps 0075 property alias solution: solution 0076 property alias solutionRect: solutionRect 0077 property alias animSol: animSol 0078 property bool keyboardNavigation: false 0079 property bool buttonsBlocked: false 0080 } 0081 0082 onStart: { Activity.start(items) } 0083 onStop: { Activity.stop() } 0084 0085 JsonParser { id: jsonParser } 0086 0087 ListModel { 0088 id: cardsModel 0089 function randPosition() { return (Math.floor(Math.random() * count)) } // choose a random position 0090 function shuffleModel() { for (var i = 0 ; i < count; i++) { move(randPosition(), randPosition(), 1) } } // shuffle elements 0091 } 0092 0093 Rectangle { 0094 id: captionBg 0095 width: caption.paintedWidth + background.baseMargins * 2 0096 height: caption.paintedHeight + background.baseMargins 0097 color: "#80FFFFFF" 0098 radius: background.baseRadius 0099 anchors.horizontalCenter: parent.horizontalCenter 0100 anchors.top: parent.top 0101 anchors.topMargin: background.baseMargins 0102 GCText { 0103 id: caption 0104 width: background.width - background.baseMargins * 4 0105 anchors.centerIn: captionBg 0106 text: qsTr("Use the four numbers with given operators to find 24.") 0107 verticalAlignment: Text.AlignVCenter 0108 horizontalAlignment: Text.AlignHCenter 0109 wrapMode: Text.WordWrap 0110 } 0111 MouseArea { 0112 anchors.fill: parent 0113 onClicked: captionBg.opacity = 0.0 0114 } 0115 } 0116 0117 Item { 0118 id: layoutArea 0119 anchors.top: captionBg.bottom 0120 anchors.bottom: score.top 0121 anchors.horizontalCenter: background.horizontalCenter 0122 anchors.margins: background.baseMargins 0123 width: Math.min(background.width - 2 * background.baseMargins, 0124 400 * ApplicationInfo.ratio) 0125 } 0126 // Main section 0127 Rectangle { // Values 0128 id: valuesArea 0129 anchors.top: layoutArea.top 0130 anchors.left: layoutArea.left 0131 width: layoutArea.width * 0.66 0132 height: Math.min(250 * ApplicationInfo.ratio, layoutArea.height * 0.75) 0133 color: "#80FFFFFF" 0134 radius: background.baseRadius 0135 GridView { 0136 id: cardsBoard 0137 anchors.fill: parent 0138 cellWidth: (parent.width - background.baseMargins) * 0.5 0139 cellHeight: (parent.height - background.baseMargins) * 0.5 0140 highlightFollowsCurrentItem: false 0141 boundsBehavior: Flickable.StopAtBounds 0142 model: cardsModel 0143 delegate: Item { // Display a card with a number inside 0144 id: cardNumber 0145 property int value: value_ 0146 width: cardsBoard.cellWidth 0147 height: cardsBoard.cellHeight 0148 Rectangle { 0149 id: cardRect 0150 width: parent.width - background.baseMargins 0151 height: parent.height - background.baseMargins 0152 anchors.top: parent.top 0153 anchors.left: parent.left 0154 anchors.margins: background.baseMargins 0155 visible: true 0156 color: (items.currentValue === index) ? background.baseColor : "#F0F0F0" 0157 border.width: (items.keyboardNavigation && items.keysOnValues && (cardsBoard.currentIndex === index)) ? background.selectionWidth : ApplicationInfo.ratio 0158 border.color: (items.keyboardNavigation && items.keysOnValues && (cardsBoard.currentIndex === index)) ? background.selectionColor : background.baseColor 0159 radius: background.baseMargins 0160 GCText { 0161 anchors.fill: parent 0162 horizontalAlignment: Text.AlignHCenter 0163 verticalAlignment: Text.AlignVCenter 0164 fontSize: hugeSize 0165 fontSizeMode: Text.Fit 0166 text: value 0167 } 0168 MouseArea { 0169 id: boardArea 0170 anchors.fill: parent 0171 enabled: animationCard.state === "" && !items.buttonsBlocked 0172 onClicked: Activity.valueClicked(index) 0173 } 0174 } 0175 } 0176 } 0177 0178 ErrorRectangle { 0179 id: errorRectangle 0180 anchors.fill: valuesArea 0181 radius: valuesArea.radius 0182 imageSize: Math.min(width, height) * 0.5 0183 function releaseControls() { items.buttonsBlocked = false; } 0184 } 0185 0186 Item { // Animation card visible during animations 0187 id: animationCard 0188 property string value: "" 0189 property string action: Activity.animActions[0] 0190 width: cardsBoard.cellWidth 0191 height: cardsBoard.cellHeight 0192 visible: false 0193 Rectangle { 0194 id: animationCardBg 0195 width: parent.width - background.baseMargins 0196 height: parent.height - background.baseMargins 0197 color: background.baseColor 0198 radius: background.baseMargins 0199 border.color: background.baseColor 0200 border.width: background.selectionWidth 0201 anchors.top: parent.top 0202 anchors.left: parent.left 0203 anchors.margins: background.baseMargins 0204 } 0205 GCText { 0206 anchors.fill: parent 0207 horizontalAlignment: Text.AlignHCenter 0208 verticalAlignment: Text.AlignVCenter 0209 fontSize: hugeSize 0210 fontSizeMode: Text.Fit 0211 text: animationCard.value 0212 } 0213 states: [ 0214 State { 0215 name: "moveto" 0216 PropertyChanges { 0217 target: animationCard 0218 visible: true 0219 x: items.cardsBoard.currentItem.x 0220 y: items.cardsBoard.currentItem.y 0221 } 0222 }, 0223 State { 0224 name: "wait" 0225 PropertyChanges { 0226 target: animationCard 0227 visible: true 0228 } 0229 PropertyChanges { 0230 target: animationCardBg 0231 color: "tomato" 0232 border.color: "tomato" 0233 } 0234 } 0235 ] 0236 transitions: [ 0237 Transition { 0238 to: "moveto" 0239 SequentialAnimation { 0240 alwaysRunToEnd: true 0241 NumberAnimation { properties: "x,y"; duration: 300 } 0242 ScriptAction { 0243 script: { 0244 animationCard.state = "" 0245 if (animationCard.action === "forward") 0246 Activity.checkResult() 0247 else if (animationCard.action === "backward") 0248 Activity.endPopOperation() 0249 } 0250 } 0251 } 0252 }, 0253 Transition { 0254 to: "wait" 0255 SequentialAnimation { 0256 alwaysRunToEnd: true 0257 PauseAnimation { duration: 800 } 0258 ScriptAction { script: { audioEffects.play('qrc:/gcompris/src/core/resource/sounds/crash.wav') } } 0259 PauseAnimation { duration: 800 } 0260 ScriptAction { script: { Activity.popOperation() }} 0261 } 0262 } 0263 ] 0264 } 0265 } 0266 0267 Rectangle { // Operators 0268 id: operatorsArea 0269 anchors.top: valuesArea.bottom 0270 anchors.topMargin: background.baseMargins 0271 anchors.left: valuesArea.left 0272 anchors.right: valuesArea.right 0273 height: Math.min(layoutArea.height - valuesArea.height - background.baseMargins, 0274 80 * ApplicationInfo.ratio) 0275 radius: background.baseRadius 0276 color: "#80FFFFFF" 0277 enabled: ((items.currentValue !== -1) && (animationCard.state === "")) 0278 ListView { 0279 id: operators 0280 anchors.fill: parent 0281 orientation: ListView.Horizontal 0282 boundsBehavior: Flickable.StopAtBounds 0283 model: [ "+", "−", "×", "÷" ] 0284 delegate: Item { 0285 width: (operatorsArea.width - background.baseMargins) * 0.25 0286 height: operatorsArea.height 0287 Rectangle { // Display an operator button 0288 id: opRect 0289 width: parent.width - background.baseMargins 0290 height: parent.height - background.baseMargins * 2 0291 anchors.top: parent.top 0292 anchors.left: parent.left 0293 anchors.margins: background.baseMargins 0294 visible: index < items.operatorsCount 0295 color: (items.currentOperator === index) ? background.baseColor : "#F0F0F0" 0296 opacity: (items.currentValue !== -1) ? 1.0 : 0.5 0297 border.width: (items.keyboardNavigation && !items.keysOnValues && (operators.currentIndex === index) && (items.currentValue !== -1)) ? background.selectionWidth : ApplicationInfo.ratio 0298 border.color: (items.keyboardNavigation && !items.keysOnValues && (operators.currentIndex === index) && (items.currentValue !== -1)) ? background.selectionColor : background.baseColor 0299 radius: background.baseMargins 0300 GCText { 0301 anchors.fill: parent 0302 horizontalAlignment: Text.AlignHCenter 0303 verticalAlignment: Text.AlignVCenter 0304 text: operators.model[index] 0305 fontSize: hugeSize 0306 fontSizeMode: Text.Fit 0307 } 0308 MouseArea { 0309 id: opArea 0310 anchors.fill: parent 0311 enabled: !items.buttonsBlocked 0312 onClicked: Activity.operatorClicked(index) 0313 } 0314 } 0315 } 0316 } 0317 } 0318 0319 Rectangle { 0320 id: stepsRect 0321 width: layoutArea.width - valuesArea.width - background.baseMargins 0322 height: Math.min(80 * ApplicationInfo.ratio, 0323 (layoutArea.height - background.baseMargins) * 0.5) 0324 anchors.top: layoutArea.top 0325 anchors.right: layoutArea.right 0326 color: "#F0F0F0" 0327 radius: background.baseRadius 0328 GCText { 0329 id: steps 0330 anchors.fill: parent 0331 anchors.leftMargin: background.baseMargins 0332 fontSize: tinySize 0333 text: "" 0334 } 0335 } 0336 0337 Rectangle { 0338 id: solutionRect 0339 width: stepsRect.width 0340 height: stepsRect.height 0341 color: "#F0F0F0" 0342 radius: background.baseRadius 0343 anchors.top: stepsRect.bottom 0344 anchors.topMargin: background.baseMargins 0345 anchors.right: layoutArea.right 0346 opacity: 0.0 0347 GCText { 0348 id: solution 0349 anchors.fill: parent 0350 anchors.leftMargin: background.baseMargins 0351 fontSize: tinySize 0352 opacity: 0.5 0353 text: "" 0354 } 0355 NumberAnimation on opacity { 0356 id: animSol 0357 property bool firstTime: true 0358 alwaysRunToEnd: true 0359 to: 0.0 0360 duration: 1000 0361 onStarted: cancelButton.visible = false 0362 onStopped: { 0363 if (!firstTime) { // animation is triggered on activity start 0364 Activity.unstack = true 0365 Activity.popOperation() 0366 } 0367 firstTime = false 0368 cardsBoard.enabled = true 0369 operators.enabled = true 0370 } 0371 } 0372 } 0373 0374 Image { 0375 id: cancelButton 0376 source: "qrc:/gcompris/src/activities/chess/resource/undo.svg" 0377 height: score.height 0378 width: height 0379 sourceSize.width: width 0380 sourceSize.height: height 0381 anchors.top: operatorsArea.bottom 0382 anchors.topMargin: background.baseMargins 0383 anchors.left: operatorsArea.left 0384 enabled: animationCard.state === "" 0385 MouseArea { 0386 anchors.fill: parent 0387 enabled: !items.buttonsBlocked 0388 onClicked: { 0389 if (solutionRect.opacity !== 0.0) { 0390 animSol.start() 0391 } else { 0392 animSol.stop() 0393 Activity.unstack = false 0394 Activity.popOperation() 0395 } 0396 } 0397 } 0398 } 0399 0400 Image { 0401 id: hintButton 0402 source: "qrc:/gcompris/src/core/resource/bar_hint.svg" 0403 height: score.height 0404 width: height 0405 sourceSize.width: width 0406 sourceSize.height: height 0407 anchors.right: operatorsArea.right 0408 anchors.top: operatorsArea.bottom 0409 anchors.topMargin: background.baseMargins 0410 enabled: animationCard.state === "" 0411 MouseArea { 0412 anchors.fill: parent 0413 enabled: !items.buttonsBlocked 0414 onClicked: { 0415 if (Activity.helpCount < 4) 0416 Activity.helpCount++ 0417 solution.text = Activity.splittedSolution.slice(0, Activity.helpCount).join("\n") 0418 solutionRect.opacity = 1.0 0419 cardsBoard.enabled = false 0420 operators.enabled = false 0421 hintButton.visible = false 0422 } 0423 } 0424 } 0425 0426 DialogChooseLevel { 0427 id: dialogActivityConfig 0428 currentActivity: activity.activityInfo 0429 0430 onSaveData: { 0431 levelFolder = dialogActivityConfig.chosenLevels 0432 currentActivity.currentLevels = dialogActivityConfig.chosenLevels 0433 ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels) 0434 } 0435 onClose: { 0436 home() 0437 } 0438 onStartActivity: { 0439 background.stop() 0440 background.start() 0441 } 0442 } 0443 0444 DialogHelp { 0445 id: dialogHelp 0446 onClose: home() 0447 } 0448 0449 Score { 0450 id: score 0451 numberOfSubLevels: items.subLevelCount 0452 currentSubLevel: 0 0453 anchors.top: undefined 0454 anchors.right: background.right 0455 anchors.rightMargin: background.baseMargins 0456 anchors.left: undefined 0457 anchors.bottom: background.bottom 0458 anchors.bottomMargin: bar.height * 1.5 0459 onStop: Activity.nextSubLevel() 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 Keys.onPressed: Activity.handleKeys(event) 0483 } 0484 }