diff --git a/src/activities/share/DropChild.qml b/src/activities/share/DropChild.qml index 5665ad0f0..0e4e7ea69 100644 --- a/src/activities/share/DropChild.qml +++ b/src/activities/share/DropChild.qml @@ -1,229 +1,226 @@ /* GCompris - DropChild.qml * * Copyright (C) 2016 Stefan Toncu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import GCompris 1.0 import "../../core" Rectangle { id: dropChild width: items.cellSize * 3 height: items.cellSize * 4.5 color: "transparent" radius: 0.2 z: 5 property string name property alias childImage: childImage property alias area: area property int indexS: index + property alias candyCount: candyCount Image { id: childImage sourceSize.width: items.cellSize * 1.5 * 0.7 sourceSize.height: items.cellSize * 1.5 - 5 anchors.bottom: area.top anchors.left: parent.left anchors.leftMargin: 20 source: "resource/images/" + name + ".svg" } //displays the number of candies each child has GCText { id: candyCount anchors.bottom: area.top anchors.right: parent.right anchors.rightMargin: 20 //"listModel.get(index) ? ... " because of an error received at startup of each level text: (listModel.get(index) && background.showCount) ? listModel.get(index).countS : "" - } Rectangle { id: area width: items.cellSize * 3 height: items.cellSize * 3 anchors.bottom: parent.bottom radius: width * 0.07 color: "#cfecf0" property var childCoordinate: repeater_drop_areas.mapToItem(background, dropChild.x, dropChild.y) property var candyCoord: candyWidget.mapToItem(background, candyWidget.element.x, candyWidget.element.y) opacity: candyCoord.x > childCoordinate.x && candyCoord.y > childCoordinate.y + childImage.height && candyCoord.x < childCoordinate.x + childCoordinate.width && candyCoord.y < childCoordinate.y + childCoordinate.height ? 0.5 : 1 MouseArea { anchors.fill: parent onClicked: { if (items.acceptCandy) - ////////////////////// START of EASY mode + // Easy mode if (background.easyMode) { if (background.currentCandies < items.totalCandies) { if (listModel.get(index).countS + 1 <= 8) { //add candies in the first rectangle - listModel.setProperty(index,"countS",listModel.get(index).countS+1) + repeater_drop_areas.itemAt(index).candyCount.text = listModel.get(index).countS + 1 + listModel.setProperty(index,"countS",listModel.get(index).countS + 1) //the current number of candies increases background.currentCandies ++ //on the last one, the candy image from top goes away (destroy) if (background.currentCandies === items.totalCandies) { background.resetCandy() candyWidget.element.opacity = 0.6 } //show the basket if there is a rest if (background.rest!=0 && background.basketShown() === false) items.basketWidget.element.opacity = 1 - } else print("onclidked else: ", listModel.get(index).countS+1 + " -------------> NO MORE") + } } else { background.resetCandy() candyWidget.element.opacity = 0.6 } - ////////////////////// END of EASY mode + // Hard mode } else { if (background.currentCandies < items.candyWidget.total) { if (listModel.get(index).countS + 1 <= 8) { //add candies in the first rectangle - listModel.setProperty(index,"countS",listModel.get(index).countS+1) + repeater_drop_areas.itemAt(index).candyCount.text = listModel.get(index).countS + 1 + listModel.setProperty(index,"countS",listModel.get(index).countS + 1) //the current number of candies increases background.currentCandies ++ //show the basket if there is a rest if (background.rest!=0 && background.basketShown() === false) items.basketWidget.element.opacity = 1 if (background.currentCandies + 1 === items.candyWidget.total) { background.resetCandy() } } else { background.wrongMove.fadeInOut.start() - print("onclidked else: ", listModel.get(index).countS+1 + " -------------> NO MORE") } } } - /////////////////// END of HARD mode } } Flow { id: candy_drop_area spacing: 5 width: parent.width height: parent.height Repeater { id: repeater_candy_drop_area model: countS Image { id: candyArea sourceSize.width: items.cellSize * 0.7 sourceSize.height: items.cellSize * 1.5 source: "resource/images/candy.svg" property int lastX property int lastY MouseArea { anchors.fill: parent //enables dragging the candie after placed drag.target: parent onPressed: { instruction.hide() //set the initial position candyArea.lastX = candyArea.x candyArea.lastY = candyArea.y //move this rectangle/grid on top of everything dropChild.z++ grid.z++ - - print("new dropChild.z " + dropChild.z + " grid.z " + grid.z) } onReleased: { //move this rectangle/grid to its previous state dropChild.z-- grid.z-- - print("orig dropChild.z " + dropChild.z + " grid.z " + grid.z) - //check where the candy is being dropped for (var i=0; i childCoordinate.x && candyCoordinate.x < childCoordinate.x + currentChild.area.width && candyCoordinate.y > childCoordinate.y + currentChild.childImage.height && candyCoordinate.y < childCoordinate.y + currentChild.childImage.height + currentChild.area.height) { //add the candy to the "i"th recthangle + repeater_drop_areas.itemAt(i).candyCount.text = listModel.get(i).countS + 1 listModel.setProperty(i, "countS", listModel.get(i).countS + 1) //remove the candy from current rectangle + repeater_drop_areas.itemAt(rect2.indexS).candyCount.text = listModel.get(rect2.indexS).countS - 1 listModel.setProperty(rect2.indexS, "countS", listModel.get(rect2.indexS).countS - 1); break; } } else { - //check if the user wants to put back the candy to the leftWidget - if (candyCoordinate.x > 0 && candyCoordinate.x < wid.width && - candyCoordinate.y > 0 && candyCoordinate.y < wid.height) { - //restore the candy to the leftWidget - background.currentCandies-- - candyWidget.element.opacity = 1 - items.candyWidget.canDrag = true - //remove the candy from current rectangle - listModel.setProperty(rect2.indexS, "countS", listModel.get(rect2.indexS).countS - 1); - break; - } + //check if the user wants to put back the candy + repeater_drop_areas.itemAt(rect2.indexS).candyCount.text = listModel.get(rect2.indexS).countS - 1 + //restore the candy to the leftWidget + background.currentCandies-- + candyWidget.element.opacity = 1 + items.candyWidget.canDrag = true + //remove the candy from current rectangle + listModel.setProperty(rect2.indexS, "countS", listModel.get(rect2.indexS).countS - 1); + break; } } //restore the candy to its initial position candyArea.x = candyArea.lastX candyArea.y = candyArea.lastY } //when clicked, it will restore the candy onClicked: { + repeater_drop_areas.itemAt(rect2.indexS).candyCount.text = listModel.get(rect2.indexS).countS - 1 background.currentCandies-- candyWidget.element.opacity = 1 items.candyWidget.canDrag = true listModel.setProperty(rect2.indexS, "countS", listModel.get(rect2.indexS).countS - 1); } } } } } } } diff --git a/src/activities/share/Share.qml b/src/activities/share/Share.qml index c9bbc0de1..89d61af9e 100644 --- a/src/activities/share/Share.qml +++ b/src/activities/share/Share.qml @@ -1,469 +1,469 @@ /* GCompris - share.qml * * Copyright (C) 2016 Stefan Toncu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import GCompris 1.0 import "../../core" import "share.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} - // TODO: handle Qt 5.7 listModel bug - pageComponent: Rectangle { id: background anchors.fill: parent color: "#ffffb3" signal start signal stop Component.onCompleted: { - dialogActivityConfig.getInitialConfiguration() + dialogActivityConfig.getInitialConfiguration() activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property alias bar: bar property alias bonus: bonus property alias instruction: instruction property int currentSubLevel: 0 property int nbSubLevel property alias listModel: listModel property bool acceptCandy: false property alias dataset: dataset property alias girlWidget: girlWidget property alias boyWidget: boyWidget property alias candyWidget: candyWidget property alias basketWidget: basketWidget property alias leftWidget: leftWidget property int totalBoys property int totalGirls property int totalCandies property int totalChildren: totalBoys + totalGirls property int barHeightAddon: ApplicationSettings.isBarHidden ? 1 : 3 property int cellSize: Math.min(background.width / 11 , background.height / (9 + barHeightAddon)) + property alias repeater_drop_areas: repeater_drop_areas } Loader { id: dataset asynchronous: false } onStart: { Activity.start(items) } onStop: { Activity.stop() } property bool vert: background.width > background.height property int currentBoys: 0 property int currentGirls: 0 property int currentCandies: 0 property int rest property int placedInGirls property int placedInBoys property bool showCount: true property bool easyMode: false property alias wrongMove: wrongMove property bool finished: false //returns true if the x and y is in the "dest" area function contains(x,y,dest) { return (x > dest.x && x < dest.x + dest.width && y > dest.y && y < dest.y + dest.height) } //stop the candy rotation function resetCandy() { items.acceptCandy = false; candyWidget.element.rotation = 0 } //searches in the board for the basket; if it exists, returns true function basketShown() { for (var i=0; i= items.totalChildren) { for (var i=0; i bad bonus.bad("flower") } //center zone Rectangle { id: grid z: 4 //map the coordinates from widgets to grid property var boy: leftWidget.mapFromItem(boyWidget, boyWidget.element.x, boyWidget.element.y) property var girl: leftWidget.mapFromItem(girlWidget, girlWidget.element.x, girlWidget.element.y) property var basket: leftWidget.mapFromItem(basketWidget, basketWidget.element.x, basketWidget.element.y) //show that the widget can be dropped here color: background.contains(boy.x, boy.y, grid) || background.contains(girl.x, girl.y, grid) || background.contains(basket.x, basket.y, grid) ? "pink" : "transparent" anchors { top: background.vert ? parent.top : leftWidget.bottom left: background.vert ? leftWidget.right : parent.left topMargin: 20 leftMargin: 20 } width: background.vert ? background.width - leftWidget.width - 40 : background.width - 40 height: ApplicationSettings.isBarHidden ? background.height : background.vert ? background.height - (bar.height * 1.1) : background.height - (bar.height * 1.1) - leftWidget.height //shows/hides the Instruction MouseArea { anchors.fill: parent onClicked: (instruction.opacity === 0) ? instruction.show() : instruction.hide() } ListModel { id: listModel } Flow { id: drop_areas spacing: 10 width: parent.width height: parent.height Repeater { id: repeater_drop_areas model: listModel DropChild { id: rect2 //"nameS" from listModel name: nameS } } } } //instruction rectangle Rectangle { id: instruction anchors.fill: instructionTxt opacity: 0.8 radius: 10 border.width: 2 z: 10 border.color: "black" gradient: Gradient { GradientStop { position: 0.0; color: "#000" } GradientStop { position: 0.9; color: "#666" } GradientStop { position: 1.0; color: "#AAA" } } property alias text: instructionTxt.text Behavior on opacity { PropertyAnimation { duration: 200 } } function show() { if(text) opacity = 1 } function hide() { opacity = 0 } } //instruction for playing the game GCText { id: instructionTxt anchors { top: background.vert ? parent.top : leftWidget.bottom topMargin: -10 horizontalCenter: grid.horizontalCenter } opacity: instruction.opacity z: instruction.z fontSize: background.vert ? regularSize : smallSize color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHCenter width: Math.max(Math.min(parent.width * 0.8, text.length * 8), parent.width * 0.3) wrapMode: TextEdit.WordWrap } //left widget, with girl/boy/candy/basket widgets in a grid Rectangle { id: leftWidget width: background.vert ? items.cellSize * 1.74 : background.width height: background.vert ? background.height : items.cellSize * 1.74 color: "#FFFF42" border.color: "#FFD85F" border.width: 4 z: 4 //grid with ok button and images of a boy, a girl, a candy and a basket Grid { id: view x: 10 y: 10 width: background.vert ? leftWidget.width : 3 * bar.height height: background.vert ? background.height - 2 * bar.height : bar.height spacing: 10 columns: background.vert ? 1 : 5 //ok button Image { id: okButton source:"qrc:/gcompris/src/core/resource/bar_ok.svg" sourceSize.width: items.cellSize * 1.5 fillMode: Image.PreserveAspectFit MouseArea { id: mouseArea anchors.fill: parent enabled: background.finished ? false : true onPressed: okButton.opacity = 0.6 onReleased: okButton.opacity = 1 onClicked: background.check() } } WidgetOption { id: girlWidget src: "resource/images/girl.svg" name: "girl" total: items.totalGirls current: background.currentGirls } WidgetOption { id: boyWidget src: "resource/images/boy.svg" name: "boy" total: items.totalBoys current: background.currentBoys } WidgetOption { id: candyWidget src: "resource/images/candy.svg" name: "candy" total: background.easyMode ? items.totalCandies : 8 * items.totalChildren + 1 current: background.currentCandies //swing animation for candies SequentialAnimation { id: anim running: items.acceptCandy ? true : false loops: Animation.Infinite NumberAnimation { target: candyWidget.element property: "rotation" from: -10; to: 10 duration: 400 + Math.floor(Math.random() * 400) easing.type: Easing.InOutQuad } NumberAnimation { target: candyWidget.element property: "rotation" from: 10; to: -10 duration: 400 + Math.floor(Math.random() * 400) easing.type: Easing.InOutQuad } } } WidgetOption { id: basketWidget src: "resource/images/basket.svg" name: "basket" element { opacity: 0 Behavior on opacity { PropertyAnimation { duration: 500 } } } } } } // show message warning for placing too many candies in one area Rectangle { id: wrongMove anchors.fill: wrongMoveText z: 5 color: "#FFFF42" radius: width / height * 10 opacity: 0 property alias fadeInOut: fadeInOut SequentialAnimation { id: fadeInOut PropertyAction { target: wrongMove; property: "z"; value: 5 } NumberAnimation { target: wrongMove; property: "opacity"; to: 1; duration: 300 } NumberAnimation { target: wrongMove; property: "opacity"; to: 1; duration: 500 } NumberAnimation { target: wrongMove; property: "opacity"; to: 0; duration: 200 } PropertyAction { target: wrongMove; property: "z"; value: -5 } } } GCText { id: wrongMoveText anchors.horizontalCenter: grid.horizontalCenter anchors.verticalCenter: parent.verticalCenter fontSize: background.vert ? hugeSize : largeSize opacity: wrongMove.opacity z: wrongMove.z color: "#404040" text: qsTr(" Too many candies!! ") } DialogActivityConfig { id: dialogActivityConfig currentActivity: activity content: Component { Item { height: column.height Column { id: column spacing: 10 width: parent.width GCDialogCheckBox { id: easyModeBox width: 250 * ApplicationInfo.ratio text: qsTr("Easy mode") checked: background.easyMode onCheckedChanged: { background.easyMode = checked if (checked == false) candyWidget.element.opacity = 1 else Activity.reloadRandom() print("easyModeBox: ",checked) } } } } } onLoadData: { if(dataToSave && dataToSave["mode"]) { background.easyMode = dataToSave["mode"]; } } - + onSaveData: { dataToSave = {"mode": background.easyMode} } + onClose: home() } //bar buttons DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level | reload | config} onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reloadRandom() onConfigClicked: { dialogActivityConfig.active = true displayDialog(dialogActivityConfig) } } Bonus { id: bonus Component.onCompleted: { win.connect(Activity.nextSubLevel) } onStop: background.finished = false } Score { anchors { bottom: parent.bottom bottomMargin: 10 * ApplicationInfo.ratio right: parent.right rightMargin: 10 * ApplicationInfo.ratio top: undefined left: undefined } numberOfSubLevels: items.nbSubLevel currentSubLevel: items.currentSubLevel + 1 } } } diff --git a/src/activities/share/WidgetOption.qml b/src/activities/share/WidgetOption.qml index 4e190d3cf..474dd6a50 100644 --- a/src/activities/share/WidgetOption.qml +++ b/src/activities/share/WidgetOption.qml @@ -1,199 +1,202 @@ /* GCompris - WidgetOption.qml * * Copyright (C) 2016 Stefan Toncu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.1 import QtQuick.Window 2.2 import GCompris 1.0 import "../../core" Rectangle { id: widget width: items.cellSize * 1.5 height: items.cellSize * 1.5 color: "transparent" //initial position of the element //(these vars are assigned to element after release of click mouse) property int lastX property int lastY property string src property int current: 0 property int total: 0 property string name property bool canDrag: true property alias element: element Image { id: element sourceSize.width: items.cellSize * 1.5 sourceSize.height: items.cellSize * 1.5 source: widget.src property alias elementText: elementText //number of available items GCText { id: elementText anchors.left: parent.left anchors.bottom: parent.bottom text: (background.showCount && widget.name !== "basket" && background.easyMode) ? widget.total - widget.current : "" } property alias dragAreaElement: dragAreaElement MouseArea { id: dragAreaElement anchors.fill: parent drag.target: (widget.canDrag) ? parent : null onPressed: { instruction.hide() if (widget.name !== "candy") background.resetCandy() //set the initial position widget.lastX = element.x widget.lastY = element.y } onReleased: { var newCoordinate = widget.mapToItem(background, element.x, element.y) var basketActive = false switch(widget.name) { case "candy": - ////////////////////// START of EASY mode + // Easy mode if (background.easyMode) { if (background.currentCandies < items.totalCandies) { items.acceptCandy = true for (var i = 0; i < listModel.count; i++) { var currentChild = repeater_drop_areas.itemAt(i) var childCoordinate = drop_areas.mapToItem(background, currentChild.x, currentChild.y) //coordinates of "boy/girl rectangle" in background coordinates if ((listModel.get(i).countS + 1) > 8) { - print("in if: ", listModel.get(i).countS+1 + " -------------> CONINTUE ------->") continue } var currentElement = element.parent.mapToItem(background, element.x, element.y) if (currentElement.x > childCoordinate.x && currentElement.x < childCoordinate.x + currentChild.area.width && currentElement.y > childCoordinate.y + currentChild.childImage.height && currentElement.y < childCoordinate.y + currentChild.childImage.height + currentChild.area.height) { - listModel.setProperty(i, "countS", listModel.get(i).countS+1) + repeater_drop_areas.itemAt(i).candyCount.text = listModel.get(i).countS + 1 + listModel.setProperty(i, "countS", listModel.get(i).countS + 1) background.currentCandies ++ } if (background.currentCandies == items.totalCandies) { widget.canDrag = false background.resetCandy() candyWidget.element.opacity = 0.6 } //find if the basket is already present on the board if (currentChild.name === "basket" && background.rest != 0) { basketActive = true } } //if there is rest and the basket is not yet present on the board, show the basket if (background.rest != 0 && basketActive === false) items.basketWidget.element.opacity = 1 } else { widget.canDrag = false background.resetCandy() element.opacity = 0.6 } - ////////////////////// END of EASY mode + // Hard mode } else { if (background.currentCandies < widget.total) { items.acceptCandy = true for (i = 0; i < listModel.count; i++) { currentChild = repeater_drop_areas.itemAt(i) childCoordinate = drop_areas.mapToItem(background, currentChild.x, currentChild.y) //coordinates of "boy/girl rectangle" in background coordinates currentElement = element.parent.mapToItem(background, element.x, element.y) if (currentElement.x > childCoordinate.x && currentElement.x < childCoordinate.x + currentChild.area.width && currentElement.y > childCoordinate.y + currentChild.childImage.height && currentElement.y < childCoordinate.y + currentChild.childImage.height + currentChild.area.height) { if ((listModel.get(i).countS + 1) > 8) { - print("in if: ", listModel.get(i).countS+1 + " -------------> CONINTUE -------> i " + i) background.wrongMove.fadeInOut.start() continue } - listModel.setProperty(i, "countS", listModel.get(i).countS+1) + repeater_drop_areas.itemAt(i).candyCount.text = listModel.get(i).countS + 1 + listModel.setProperty(i, "countS", listModel.get(i).countS + 1) background.currentCandies ++ } } // if all the "dropAreas" are full with 8 candies, then stop the "swing" effect of the candy in leftWidget if (background.currentCandies + 1 == widget.total) background.resetCandy() } } - /////////////////// END of HARD mode break; case "basket": if (background.contains(newCoordinate.x, newCoordinate.y, grid)) { if (widget.canDrag) { widget.canDrag = false widget.element.opacity = 0 listModel.append({countS: 0, nameS: "basket"}); } } break; //default is for "boy" and "girl" default: if (background.contains(newCoordinate.x, newCoordinate.y, grid)) { if (widget.current < widget.total) { if (widget.canDrag) { widget.current ++ listModel.append({countS: 0, nameS: widget.name}); - // set the candies already "preset" - if (widget.name == "boy") + // set the candies already "present" + if (widget.name == "boy") { + repeater_drop_areas.itemAt(listModel.count-1).candyCount.text = background.placedInBoys listModel.setProperty(listModel.count-1, "countS", background.placedInBoys) - if (widget.name == "girl") + } + if (widget.name == "girl") { + repeater_drop_areas.itemAt(listModel.count-1).candyCount.text = background.placedInGirls listModel.setProperty(listModel.count-1, "countS", background.placedInGirls) + } if (widget.current === widget.total) { widget.canDrag = false element.opacity = 0.6 } } } else widget.canDrag = false } } //set the widget to its initial coordinates element.x = widget.lastX element.y = widget.lastY } } } }