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

0001 /* GCompris - Superbrain.qml
0002  *
0003  * SPDX-FileCopyrightText: 2015 Holger Kaelberer <holger.k@elberer.de>
0004  *
0005  * Authors:
0006  *   Bruno Coudoin <bruno.coudoin@gcompris.net> (GTK+ version)
0007  *   Holger Kaelberer <holger.k@elberer.de> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 import QtQuick 2.12
0012 
0013 import "../../core"
0014 import "superbrain.js" as Activity
0015 import GCompris 1.0
0016 
0017 ActivityBase {
0018     id: activity
0019 
0020     onStart: focus = true
0021     onStop: {}
0022 
0023     pageComponent: Image {
0024         id: background
0025         source: "qrc:/gcompris/src/activities/family/resource/background.svg"
0026         sourceSize.width: width
0027         sourceSize.height: height
0028         fillMode: Image.PreserveAspectCrop
0029         focus: true
0030 
0031         readonly property double scaleFactor: 1
0032         readonly property bool isPortrait: (height >= width)
0033 
0034         signal start
0035         signal stop
0036 
0037         MouseArea {
0038             anchors.fill: parent
0039             onClicked: showChooser(false);
0040         }
0041 
0042         Component.onCompleted: {
0043             dialogActivityConfig.initialize()
0044             activity.start.connect(start)
0045             activity.stop.connect(stop)
0046         }
0047 
0048         QtObject {
0049             id: items
0050             property Item main: activity.main
0051             property alias background: background
0052             property int currentLevel: activity.currentLevel
0053             property alias bonus: bonus
0054             property alias score: score
0055             property alias colorsRepeater: colorsRepeater
0056             property alias chooserGrid: chooserGrid
0057             property alias guessModel: guessModel
0058             property alias guessColumn: guessColumn
0059             property alias currentRepeater: currentRepeater
0060             property string mode: "color"
0061             property GCSfx audioEffects: activity.audioEffects
0062             property bool buttonsBlocked: false
0063         }
0064 
0065         onStart: { Activity.start(items) }
0066         onStop: {
0067             chooserTimer.stop()
0068             Activity.stop()
0069         }
0070 
0071         Column {
0072             id: colorsColumn
0073 
0074             anchors.left: parent.left
0075             anchors.leftMargin: 5 * ApplicationInfo.ratio
0076             anchors.top: parent.top
0077             anchors.topMargin: 5 * ApplicationInfo.ratio
0078 
0079             spacing: 3  * ApplicationInfo.ratio
0080 
0081             width: guessColumn.guessSize
0082             height: guessColumn.guessSize
0083 
0084             add: Transition {
0085                 NumberAnimation { properties: "y"; duration: 1000; easing.type: Easing.OutBounce }
0086             }
0087 
0088             Repeater {
0089                 id: colorsRepeater
0090 
0091                 model: ListModel {}
0092 
0093                 delegate: SearchItem {
0094                     width: 40 * ApplicationInfo.ratio
0095                     height: 40 * ApplicationInfo.ratio
0096                     border.width: 2
0097                     border.color: "#373737"
0098                     searchItemIndex: itemIndex
0099                 }
0100             }
0101         }
0102 
0103         Rectangle {
0104             id: tooltipRect
0105             width: 100 * ApplicationInfo.ratio
0106             height: tooltipText.height + 10 * ApplicationInfo.ratio
0107             radius: 4
0108             x: 0
0109             y: 0
0110             color: "lightgray"
0111             opacity: 0
0112             z: 10
0113             property alias text: tooltipText.text
0114 
0115             GCText {
0116                 id: tooltipText
0117                 anchors.centerIn: parent
0118                 fontSize: 13
0119                 text: ""
0120                 color: "black"
0121 
0122                 onTextChanged: parent.width = width + 10
0123             }
0124 
0125             Behavior on opacity {
0126                 NumberAnimation { duration: 100 }
0127             }
0128         }
0129 
0130         function showTooltip(visible, status, mouseArea)
0131         {
0132             if (!visible || status === Activity.STATUS_UNKNOWN) {
0133                 tooltipRect.opacity = 0;
0134                 return;
0135             }
0136             showChooser(false);
0137 
0138             var obj = background.mapFromItem(mouseArea, mouseArea.mouseX, mouseArea.mouseY);
0139 
0140             if (status === Activity.STATUS_CORRECT)
0141                 tooltipRect.text = qsTr("This item is well placed.");
0142             if (status === Activity.STATUS_MISPLACED)
0143                 tooltipRect.text = qsTr("This item is misplaced.");
0144             tooltipRect.x = obj.x - 5 - tooltipRect.width;
0145             tooltipRect.y = obj.y - 5 - tooltipRect.height;
0146             tooltipRect.opacity = 0.9;
0147         }
0148 
0149         function showChooser(visible, guessIndex, item)
0150         {
0151             if (!visible) {
0152                 chooserTimer.stop();
0153                 chooser.scale = 0;
0154                 return;
0155             }
0156             var modelObj = guessModel.get(0).guess.get(guessIndex);
0157             var absolute = currentRow.mapToItem(background, item.x, item.y);
0158             chooserGrid.colIndex = modelObj.colIndex;
0159             chooserGrid.guessIndex = guessIndex;
0160             var chooserOffset = 0.5*chooser.width - item.width/2;
0161             var arrowOffset = 0;
0162             var targetX = item.x - chooserOffset;
0163             // beyond left screen border:
0164             if (absolute.x - chooserOffset < 0) {
0165                 arrowOffset = absolute.x - chooserOffset;
0166                 targetX -= arrowOffset;
0167             }
0168             // beyond right screen border:
0169             if (absolute.x + chooserOffset + item.width > background.width) {
0170                 arrowOffset = absolute.x + chooserOffset + item.width - background.width;
0171                 targetX -= arrowOffset;
0172             }
0173 
0174             chooser.x = targetX;
0175             chooser.arrowOffset = arrowOffset;
0176             var targetY = item.y - chooser.height - 15;
0177             var targetAbove = true;
0178             /* //only on top-level, at window border:
0179 if (targetY < 0) {
0180                 targetY = item.y + guessColumn.guessSize + 10;
0181                 targetAbove = false;
0182             }*/
0183             chooser.y = targetY;
0184             chooser.above = targetAbove;
0185             chooser.scale = 1;
0186             chooser.visible = true;
0187             chooserTimer.restart();
0188             //console.log("XXX chooser at item.x=" + item.x + " absolute.x=" + absolute.x + " chooser.x/w=" + chooser.x + "/" + chooser.width + " background.width=" + background.width + " currentRow.x/y/w/h=" + currentRow.x + "/" + currentRow.y + "/" + currentRow.width + "/" + currentRow.height + " guessIdx=" + guessIndex + " arrowOff=" + arrowOffset);
0189         }
0190 
0191         Item {
0192             id: currentWrapper
0193 
0194             width: currentRow.width
0195             height: currentRow.height
0196             z: 8
0197 
0198             anchors.horizontalCenter: parent.horizontalCenter
0199             anchors.bottomMargin: 20 * ApplicationInfo.ratio
0200 
0201             state: ApplicationSettings.isBarHidden ? "hidden" : "shown"
0202             states: [
0203                 State {
0204                     name: "hidden"
0205                     when: ApplicationSettings.isBarHidden
0206                     AnchorChanges {
0207                         target: currentWrapper;
0208                         anchors.bottom: parent.bottom
0209                     }
0210                 },
0211                 State {
0212                     name: "shown"
0213                     when: !ApplicationSettings.isBarHidden
0214                     AnchorChanges {
0215                         target: currentWrapper;
0216                         anchors.bottom: bar.top
0217                     }
0218                 }
0219             ]
0220 
0221             transitions: Transition {
0222                 AnchorAnimation { duration: 800; easing.type: Easing.OutBounce }
0223             }
0224 
0225             Rectangle {
0226                 id: chooser
0227 
0228                 width: chooserGrid.width + 15
0229                 height: chooserGrid.height + 15
0230 
0231                 color: "darkgray"
0232                 border.width: 0
0233                 border.color: "white"
0234 
0235                 opacity: 1
0236                 scale: 0
0237                 visible: false
0238                 z: 10
0239 
0240                 property bool above: true
0241                 property real arrowOffset: 0
0242 
0243                 Rectangle {
0244                     id: chooserArrow
0245                     width: 10
0246                     height: 10
0247 
0248                     x: chooser.width / 2 - 5 + chooser.arrowOffset
0249                     y: chooser.above ? (chooser.height - 5) : (-5)
0250                     color: chooser.color
0251                     z: chooser.z
0252                     transform: Rotation { origin.x: 5; origin.y: 5; angle: 45}
0253                 }
0254 
0255                 GridView {
0256                     id: chooserGrid
0257 
0258                     cellWidth: guessColumn.guessSize * 2
0259                     cellHeight: guessColumn.guessSize * 2
0260                     width: Math.ceil(count / 2) * cellWidth
0261                     height: 2 * cellHeight
0262                     anchors.centerIn: parent
0263                     z: 11
0264 
0265                     clip: false
0266                     interactive: false
0267                     verticalLayoutDirection: GridView.TopToBottom
0268                     layoutDirection: Qt.LeftToRight
0269                     flow: GridView.FlowLeftToRight
0270 
0271                     property int colIndex: 0
0272                     property int guessIndex: 0
0273 
0274                     Timer {
0275                         id: chooserTimer
0276                         interval: 5000
0277                         onTriggered: showChooser(false);
0278                     }
0279 
0280                     model: new Array()
0281 
0282                     delegate: SearchItem {
0283                         id: chooserItem
0284                         width: chooserGrid.cellWidth
0285                         height: chooserGrid.cellWidth
0286                         border.width: index == chooserGrid.colIndex ? 3 : 1
0287                         border.color: index == chooserGrid.colIndex ? "#373737" : "darkgray"
0288                         highlightSymbol: index == chooserGrid.colIndex
0289                         searchItemIndex: modelData
0290                         radius: 5
0291 
0292                         MouseArea {
0293                             id: chooserMouseArea
0294                             anchors.fill: parent
0295                             acceptedButtons: Qt.LeftButton
0296                             enabled: chooser.scale !== 0 && !bonus.isPlaying
0297                             z: 11
0298                             hoverEnabled: ApplicationInfo.isMobile ? false : true
0299 
0300                             onClicked: {
0301                                 chooserGrid.colIndex = chooserItem.searchItemIndex;
0302                                 var obj = items.guessModel.get(0);
0303                                 obj.guess.setProperty(chooserGrid.guessIndex, "colIndex", chooserGrid.colIndex);
0304                                 showChooser(false);
0305                             }
0306                         }
0307                     }
0308                 }
0309                 Behavior on scale {
0310                     NumberAnimation { duration: 100 }
0311                 }
0312             }
0313 
0314             Row {
0315                 id: currentRow
0316                 visible: true
0317 
0318                 property double factor: 1.9
0319 
0320                 anchors.left: parent.left
0321                 anchors.top: parent.top
0322 
0323                 spacing: guessColumn.horizSpacing * factor
0324                 height: guessColumn.guessSize * factor
0325                 scale: 1
0326                 z: 9
0327 
0328                 Repeater {
0329                     id: currentRepeater
0330 
0331                     delegate: SearchItem {
0332                         id: currentGuess
0333 
0334                         width: guessColumn.guessSize * currentRow.factor
0335                         height: guessColumn.guessSize * currentRow.factor
0336                         border.width: 2 * currentRow.factor
0337                         border.color: "#373737"
0338                         searchItemIndex: colIndex
0339                         opacity: 1.0
0340                         z: 2
0341 
0342                         MouseArea {
0343                             id: mouseArea
0344                             anchors.fill: parent
0345                             acceptedButtons: Qt.LeftButton | Qt.RightButton
0346                             enabled: !bonus.isPlaying
0347                             z: 3
0348                             hoverEnabled: ApplicationInfo.isMobile ? false : true
0349 
0350                             onPressAndHold: {
0351                                 if (guessColumn.count > 1)
0352                                     guessModel.get(0).guess.get(index).colIndex = guessModel.get(1).guess.get(index).colIndex;
0353                             }
0354 
0355                             onClicked: {
0356                                 var obj = items.guessModel.get(0).guess.get(index);
0357                                 if(chooserTimer.running && chooserGrid.guessIndex === index) {
0358                                     if (mouse.button == Qt.LeftButton)
0359                                         obj.colIndex = (obj.colIndex ==
0360                                                         Activity.currentIndeces.length - 1) ? 0 : obj.colIndex + 1;
0361                                     else
0362                                         obj.colIndex = (obj.colIndex == 0) ?
0363                                                     Activity.currentIndeces.length - 1 : obj.colIndex - 1;
0364                                 }
0365                                 showChooser(true, index, parent);
0366                             }
0367                         }
0368                         states: State {
0369                             name: "scaled"; when: mouseArea.containsMouse
0370                             PropertyChanges {
0371                                 target: currentGuess
0372                                 scale: 1.1
0373                             }
0374                         }
0375                         transitions: Transition {
0376                             NumberAnimation { properties: "scale"; easing.type: Easing.OutCubic }
0377                         }
0378                     }
0379                 }
0380 
0381                 BarButton {
0382                     id: okButton
0383                     enabled: !items.buttonsBlocked
0384                     source: "qrc:/gcompris/src/core/resource/bar_ok.svg"
0385                     sourceSize.width: 66 * bar.barZoom
0386                     width: guessColumn.guessSize * currentRow.factor
0387                     height: guessColumn.guessSize * currentRow.factor
0388                     visible: true
0389                     z: 8
0390                     onClicked: {
0391                         showChooser(false);
0392                         Activity.checkGuess();
0393                     }
0394                 }
0395             }
0396         }
0397 
0398         ListModel {
0399             id: guessModel
0400             dynamicRoles: true
0401         }
0402 
0403         ListView {
0404             id: guessColumn
0405 
0406             anchors.horizontalCenter: parent.horizontalCenter
0407             anchors.bottom: currentWrapper.top
0408             anchors.bottomMargin: 10 * ApplicationInfo.ratio
0409 
0410             boundsBehavior: Flickable.DragOverBounds
0411             verticalLayoutDirection: ListView.BottomToTop
0412 
0413             readonly property int guessSize: 30 * ApplicationInfo.ratio
0414             readonly property int vertSpacing: 15 * ApplicationInfo.ratio
0415             readonly property int horizSpacing: 15 * ApplicationInfo.ratio
0416             readonly property int statusMargin: 5 * ApplicationInfo.ratio
0417             readonly property int resultSize: 10 * ApplicationInfo.ratio
0418             readonly property int guessColWidth: Activity.maxPieces * (guessSize + (2 * guessColumn.statusMargin))
0419                                                  + (Activity.maxPieces-1) * horizSpacing;
0420             readonly property int resultColWidth: Activity.maxPieces * resultSize
0421                                                   + (Activity.maxPieces-1) * 2;
0422 
0423             spacing: vertSpacing
0424 
0425             width: guessColWidth + 10 + (2 * horizSpacing) + resultColWidth
0426             height: count * (guessSize + vertSpacing)
0427 
0428             displaced: Transition {
0429                 NumberAnimation { easing.type: Easing.OutCubic; properties: "y"; duration: 300 }
0430             }
0431 
0432             model: guessModel
0433 
0434             delegate: Row {
0435                 id: guessRow
0436                 width: guessColumn.width
0437                 height: guessColumn.guessSize
0438                 spacing: guessColumn.horizSpacing
0439                 property int rowIndex: index
0440                 visible: index != 0
0441 
0442                 Item {
0443                     id: guessRowSpacer
0444                     width: guessColumn.guessColWidth -
0445                            (guessRepeater.count * (guessColumn.guessSize +
0446                                                    (2 * guessColumn.statusMargin) + guessColumn.horizSpacing))
0447                     height: parent.height
0448                 }
0449 
0450                 Repeater {
0451                     id: guessRepeater
0452                     anchors.left: parent.left
0453                     anchors.top: parent.top
0454                     model: guess
0455 
0456                     delegate: Item { // wrapper needed for singleGuessStatusRect's opacity
0457                         id: singleGuessWrapper
0458 
0459                         width: guessColumn.guessSize + (2 * guessColumn.statusMargin);
0460                         height: guessColumn.guessSize + (2 * guessColumn.statusMargin);
0461 
0462                         Rectangle {
0463                             id: singleGuessStatusRect
0464                             border.width: 2
0465                             border.color: (status == Activity.STATUS_CORRECT) ? "white" : "black";
0466                             anchors.fill: parent
0467                             radius: 3
0468                             color: (status == Activity.STATUS_CORRECT) ? "black" : "white";
0469                             opacity: (status == Activity.STATUS_UNKNOWN) ? 0 : 0.9
0470                             z: 1
0471 
0472                             MouseArea {
0473                                 id: mouseAreaRect
0474                                 anchors.fill: parent
0475                                 acceptedButtons: Qt.LeftButton
0476                                 enabled: guessRow.rowIndex > 0 && !bonus.isPlaying
0477                                 z: 4
0478                                 hoverEnabled: ApplicationInfo.isMobile ? false : true
0479 
0480                                 Timer {
0481                                     id: tooltipTimer
0482                                     repeat: false
0483                                     interval: 500
0484                                     signal stopTimer
0485 
0486                                     Component.onCompleted: {
0487                                         activity.stop.connect(stopTimer);
0488                                     }
0489 
0490                                     onStopTimer: {
0491                                         stop();
0492                                     }
0493 
0494                                     onTriggered: showTooltip(true, status, mouseAreaRect)
0495                                 }
0496 
0497                                 onEntered: tooltipTimer.restart()
0498 
0499                                 onExited: {
0500                                     tooltipTimer.stop()
0501                                     showTooltip(false)
0502                                 }
0503 
0504                                 onClicked: showTooltip(true, status, mouseAreaRect);
0505                                 onDoubleClicked: Activity.ackColor(index, colIndex);
0506 
0507                             }
0508                         }
0509 
0510                         SearchItem {
0511                             id: singleGuess
0512 
0513                             width: guessColumn.guessSize
0514                             height: guessColumn.guessSize
0515                             anchors.left: parent.left
0516                             anchors.top: parent.top
0517                             anchors.leftMargin: guessColumn.statusMargin
0518                             anchors.topMargin: guessColumn.statusMargin
0519 
0520                             border.width: 2
0521                             border.color: "#373737"
0522                             searchItemIndex: colIndex
0523                             opacity: 1.0
0524                             z: 2
0525 
0526                             Image {
0527                                 id: okImage
0528                                 visible: isAcked
0529 
0530                                 width: parent.width / 2
0531                                 height: parent.height / 2
0532 
0533                                 anchors.centerIn: parent
0534 
0535                                 source: "qrc:/gcompris/src/core/resource/apply.svg"
0536                             }
0537 
0538                             MouseArea {
0539                                 id: ackMouseArea
0540                                 anchors.fill: parent
0541                                 acceptedButtons: Qt.LeftButton
0542                                 enabled: status == Activity.STATUS_UNKNOWN && !bonus.isPlaying
0543                                 visible: status == Activity.STATUS_UNKNOWN
0544                                 z: 3
0545                                 hoverEnabled: ApplicationInfo.isMobile ? false : true
0546 
0547                                 onDoubleClicked: Activity.ackColor(index, colIndex);
0548                             }
0549                         }
0550                     }
0551                 }
0552 
0553                 Item {
0554                     id: guessRowSpacer2
0555                     width: 10
0556                     height: guessColumn.guessSize
0557                 }
0558 
0559                 Column {
0560                     id: guessResultColumn
0561 
0562                     width: guessColumn.resultColWidth
0563                     height: guessColumn.guessSize
0564                     spacing: 2
0565 
0566                     Item {
0567                         id: guessResultColSpacer
0568                         width: guessResultColumn.width
0569                         height: (guessResultColumn.height - 2 * (guessColumn.resultSize))
0570                     }
0571 
0572                     Row {
0573                         id: guessResultCorrectRow
0574 
0575                         width: guessResultColumn.width
0576                         height: guessColumn.resultSize
0577                         spacing: 2
0578 
0579                         Repeater {
0580                             id: guessResultCorrectRepeater
0581 
0582                             model: result.correct
0583                             delegate: Rectangle {
0584                                 id: singleCorrectResult
0585 
0586                                 width: guessColumn.resultSize
0587                                 height: guessColumn.resultSize
0588 
0589                                 radius: width * 0.5
0590                                 border.width: 1
0591                                 border.color: "white"
0592                                 color: "black"
0593                             }
0594                         }
0595                     }
0596 
0597                     Row {
0598                         id: guessResultMisplacedRow
0599 
0600                         width: guessResultColumn.width
0601                         height: guessColumn.resultSize
0602                         spacing: 2
0603 
0604                         Repeater {
0605                             id: guessResultMisplacedRepeater
0606 
0607                             model: result.misplaced
0608                             delegate: Rectangle {
0609                                 id: singleMisplacedResult
0610 
0611                                 width: guessColumn.resultSize
0612                                 height: guessColumn.resultSize
0613 
0614                                 radius: width * 0.5
0615                                 border.width: 1
0616                                 border.color: "black"
0617                                 color: "white"
0618                             }
0619                         }
0620                     }
0621                 }
0622             }
0623         }
0624 
0625         DialogHelp {
0626             id: dialogHelp
0627             onClose: home()
0628         }
0629 
0630         DialogChooseLevel {
0631             id: dialogActivityConfig
0632             currentActivity: activity.activityInfo
0633             onClose: {
0634                 home()
0635             }
0636             onLoadData: {
0637                 if(activityData && activityData["mode"]) {
0638                     items.mode = activityData["mode"];
0639                 }
0640             }
0641         }
0642 
0643         Bar {
0644             id: bar
0645             level: items.currentLevel + 1
0646             content: BarEnumContent { value: help | home | level | activityConfig }
0647             onHelpClicked: {
0648                 displayDialog(dialogHelp)
0649             }
0650             onPreviousLevelClicked: Activity.previousLevel()
0651             onNextLevelClicked: Activity.nextLevel()
0652             onHomeClicked: activity.home()
0653             onActivityConfigClicked: {
0654                 displayDialog(dialogActivityConfig)
0655             }
0656         }
0657 
0658         Bonus {
0659             id: bonus
0660             Component.onCompleted: win.connect(Activity.nextLevel)
0661         }
0662 
0663         Score {
0664             id: score
0665             anchors.bottom: undefined
0666             anchors.rightMargin: 10 * ApplicationInfo.ratio
0667             anchors.topMargin: 10 * ApplicationInfo.ratio
0668             anchors.left: undefined
0669             anchors.top: parent.top
0670             anchors.right: parent.right
0671             onStop: Activity.nextSubLevel()
0672         }
0673     }
0674 }