diff --git a/src/activities/share/BasketWidget.qml b/src/activities/share/BasketWidget.qml index 9dcf83868..bde642f88 100644 --- a/src/activities/share/BasketWidget.qml +++ b/src/activities/share/BasketWidget.qml @@ -1,46 +1,45 @@ /* GCompris - BasketWidget.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.6 import GCompris 1.0 import "../../core" WidgetOption { id: widget src: "resource/images/basket.svg" name: "basket" availableItems: "" releaseElement: function() { var newCoordinate = widget.mapToItem(background, element.x, element.y) if (background.contains(newCoordinate.x, newCoordinate.y, grid)) { if (widget.canDrag) { widget.canDrag = false - widget.element.opacity = 0 + widget.element.opacity = 0.6 listModel.append({countS: 0, nameS: "basket"}); } } } element { opacity: 0 - Behavior on opacity { PropertyAnimation { duration: 500 } } } } diff --git a/src/activities/share/DropChild.qml b/src/activities/share/DropChild.qml index d69089861..d9dc5d3b1 100644 --- a/src/activities/share/DropChild.qml +++ b/src/activities/share/DropChild.qml @@ -1,229 +1,230 @@ /* 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.6 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 width: items.cellSize sourceSize.width: width anchors.bottom: area.top anchors.left: parent.left anchors.leftMargin: 20 source: "resource/images/" + name + ".svg" fillMode: Image.PreserveAspectFit } //displays the number of candies each child has GCText { id: candyCount + color: "#373737" 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" + color: "#f2f2f2" property var childCoordinate: repeaterDropAreas.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) { // Easy mode if (background.easyMode) { if (background.currentCandies < items.candyWidget.total) { if (listModel.get(index).countS + 1 <= items.maxNumberOfCandiesPerWidget) { //add candies in the first rectangle repeaterDropAreas.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.candyWidget.total) { background.resetCandy() candyWidget.element.opacity = 0.6 } } } else { background.resetCandy() candyWidget.element.opacity = 0.6 } } // Hard mode else { if (background.currentCandies < items.candyWidget.total) { if (listModel.get(index).countS + 1 <= items.maxNumberOfCandiesPerWidget) { //add candies in the first rectangle repeaterDropAreas.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 ++ if (background.currentCandies + 1 === items.candyWidget.total) { background.resetCandy() } } else { background.wrongMove.visible = true } } } } } } Flow { id: candyDropArea spacing: 5 width: parent.width height: parent.height Repeater { id: repeaterCandyDropArea model: countS Image { id: candyArea sourceSize.width: items.cellSize * 0.6 sourceSize.height: items.cellSize * 1.2 source: "resource/images/candy.svg" fillMode: Image.PreserveAspectFit property int lastX property int lastY MouseArea { anchors.fill: parent //enables dragging the candy 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++ } function childContainsCandy(currentChild, candy) { //coordinates of "boy/girl rectangle" in background coordinates var child = dropAreas.mapToItem(items.background, currentChild.x, currentChild.y) return (candy.x > child.x && candy.x < child.x + currentChild.area.width && candy.y > child.y + currentChild.childImage.height && candy.y < child.y + currentChild.childImage.height + currentChild.area.height) } onReleased: { //move this rectangle/grid to its previous state dropChild.z-- var candyCoordinate = candyArea.parent.mapToItem(background, candyArea.x, candyArea.y) //check where the candy is being dropped for (var i = 0 ; i < listModel.count ; i++) { var currentChild = repeaterDropAreas.itemAt(i) if (currentChild !== dropChild) { //check if the user wants to put a candy to another rectangle if (childContainsCandy(currentChild, candyCoordinate)) { // don't drop more than the maximum of allowed candies per widget if(listModel.get(currentChild.indexS).countS >= items.maxNumberOfCandiesPerWidget) { background.wrongMove.visible = true break; } //add the candy to the i-th rectangle repeaterDropAreas.itemAt(i).candyCount.text = listModel.get(i).countS + 1 listModel.setProperty(i, "countS", listModel.get(i).countS + 1) //remove the candy from current rectangle repeaterDropAreas.itemAt(rect2.indexS).candyCount.text = listModel.get(rect2.indexS).countS - 1 listModel.setProperty(rect2.indexS, "countS", listModel.get(rect2.indexS).countS - 1); break; } } else if (childContainsCandy(currentChild, candyCoordinate)) { //check if the user wants to put back the candy repeaterDropAreas.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: { repeaterDropAreas.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 06adf8a79..45e6de940 100644 --- a/src/activities/share/Share.qml +++ b/src/activities/share/Share.qml @@ -1,433 +1,427 @@ /* 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.6 import GCompris 1.0 import "../../core" import "share.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent - color: "#ffffb3" + color: "#abcdef" signal start signal stop Component.onCompleted: { 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.round(Math.min(background.width / 11, background.height / (9 + barHeightAddon))) property alias repeaterDropAreas: repeaterDropAreas property int maxNumberOfCandiesPerWidget: 8 } 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: true 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 } //check if the answer is correct function check() { background.resetCandy() background.finished = true var ok = 0 var okRest = 0 if (listModel.count >= items.totalChildren) { for (var i = 0 ; i < listModel.count ; i++) { if (listModel.get(i).nameS === "basket") okRest = listModel.get(i).countS else if (listModel.get(i).countS === Math.floor(items.totalCandies/items.totalChildren)) ok ++ } //condition without rest if (rest == 0 && ok == items.totalChildren) { bonus.good("flower") return } //condition with rest else if (rest == okRest && ok == items.totalChildren) { bonus.good("tux") return } } //else => 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" + background.contains(basket.x, basket.y, grid) ? "#d5e6f7" : "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 // first hide the wrong move if visible, then show/hide instruction onClicked: wrongMove.visible ? wrongMove.visible = false : (instruction.opacity === 0) ? instruction.show() : instruction.hide() } ListModel { id: listModel } Flow { id: dropAreas spacing: 10 width: parent.width height: parent.height Repeater { id: repeaterDropAreas 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" } - } - + border.color: "#DDD" + color: "#373737" + property alias text: instructionTxt.text Behavior on opacity { PropertyAnimation { duration: 200 } } //shows/hides the Instruction MouseArea { anchors.fill: parent onClicked: instruction.hide() enabled: instruction.opacity !== 0 } 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" + color: "#5a9de0" + border.color: "#3f81c4" 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() } } ChildWidget { id: girlWidget name: "girl" total: items.totalGirls current: background.currentGirls placedInChild: background.placedInGirls } ChildWidget { id: boyWidget name: "boy" total: items.totalBoys current: background.currentBoys placedInChild: background.placedInBoys } BasketWidget { id: basketWidget } CandyWidget { id: candyWidget total: background.easyMode ? items.totalCandies : 8 * items.totalChildren + 1 current: background.currentCandies element.opacity: background.easyMode ? 1 : 0 } } } // show message warning for placing too many candies in one area Rectangle { id: wrongMove z: 5 color: "orange" radius: width / height * 10 visible: false width: grid.width height: grid.height / 3 anchors.centerIn: grid MouseArea { anchors.fill: parent onClicked: parent.visible = false } GCText { id: wrongMoveText horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: parent.width - 2 // -2 for margin height: parent.height fontSizeMode: Text.Fit wrapMode: Text.WordWrap color: "#404040" text: qsTr("You can't put more than %1 pieces of candy in the same rectangle").arg(items.maxNumberOfCandiesPerWidget) } } DialogActivityConfig { id: dialogActivityConfig currentActivity: activity content: Component { Item { height: column.height Column { id: column spacing: 10 width: parent.width GCDialogCheckBox { id: easyModeBox width: dialogActivityConfig.width text: qsTr("Display candy counter") checked: background.easyMode onCheckedChanged: { background.easyMode = checked Activity.reloadRandom() } } } } } onLoadData: { if(dataToSave && dataToSave["mode"]) { background.easyMode = (dataToSave["mode"] === "true"); } } 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 { left: undefined right: leftWidget.right bottom: background.vert ? bar.top : leftWidget.bottom margins: 3 * ApplicationInfo.ratio } width: girlWidget.width height: background.vert ? (girlWidget.height * 0.8) : girlWidget.height numberOfSubLevels: items.nbSubLevel currentSubLevel: items.currentSubLevel + 1 } } } diff --git a/src/activities/share/WidgetOption.qml b/src/activities/share/WidgetOption.qml index d7d02f44d..fd950b1da 100644 --- a/src/activities/share/WidgetOption.qml +++ b/src/activities/share/WidgetOption.qml @@ -1,84 +1,86 @@ /* 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.6 import GCompris 1.0 import "../../core" Rectangle { id: widget width: element.opacity > 0 ? items.cellSize * 1.5 : 0 height: width 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 property string availableItems // callback defined in each widget called when we release the element in background property var releaseElement: null Image { id: element fillMode: Image.PreserveAspectFit width: items.cellSize sourceSize.width: width source: widget.src } //number of available items GCText { id: elementText anchors.left: element.right anchors.bottom: element.bottom text: availableItems + color: "#f2f2f2" } + property alias dragAreaElement: dragAreaElement MouseArea { id: dragAreaElement anchors.fill: parent drag.target: (widget.canDrag) ? element : null enabled: element.opacity > 0 onPressed: { instruction.hide() if (widget.name !== "candy") background.resetCandy() //set the initial position widget.lastX = element.x widget.lastY = element.y } onReleased: { widget.releaseElement() //set the widget to its initial coordinates element.x = widget.lastX element.y = widget.lastY } } }