diff --git a/src/activities/categorization/CategoryReview.qml b/src/activities/categorization/CategoryReview.qml index f7bdb796a..7c99026e4 100644 --- a/src/activities/categorization/CategoryReview.qml +++ b/src/activities/categorization/CategoryReview.qml @@ -1,305 +1,284 @@ /* GCompris - CategoryReview.qml * * Copyright (C) 2016 Divyam Madaan * * Authors: * Divyam Madaan * * 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 "categorization.js" as Activity Item { id: rootItem property alias repeater: repeater property alias leftZoneRepeater: leftZoneRepeater property alias rightZoneRepeater: rightZoneRepeater property alias score: score property alias categoryDataset: categoryDataset property alias instructionBox: instructionBox property bool isDropped: true property bool leftAreaContainsDrag: false property bool rightAreaContainsDrag: false property bool started: rootItem.opacity == 1 property bool horizontalLayout: categoryBackground.width > categoryBackground.height property alias leftZoneModel: leftZoneModel property alias leftZone: leftZone property alias rightZone: rightZone property alias rightZoneModel: rightZoneModel + property alias leftScreen: leftScreen + property alias middleScreen: middleScreen + property alias rightScreen: rightScreen anchors.fill: parent Loader { id: categoryDataset asynchronous: false } ListModel { id: leftZone } ListModel { id: rightZone } Image { id: categoryBackground source: "qrc:/gcompris/src/activities/categorization/resource/background.svg" anchors.fill: parent sourceSize.width:parent.width Flow { id:leftZoneModel width: parent.width/3 height: parent.height spacing: 20 - anchors { - left: parent.left - top: categoryBackground.top - bottom: categoryBackground.bottom - } + x: 0 Repeater { id: leftZoneRepeater model: leftZone Item { id: leftZoneItem width: middleScreen.width*0.32 height: categoryBackground.height * 0.2 opacity: 1 Zone { id: image source: name } } } } Rectangle { id: leftScreen - anchors.fill: leftZoneModel + width: parent.width/3 + height: parent.height + x: 0 color: leftAreaContainsDrag ? "#9933FF" : "red" opacity: 0.52 } Flow { id: rightZoneModel width: parent.width/3.2 height: parent.height spacing: 15 - anchors { - right: parent.right - bottom: categoryBackground.bottom - top: categoryBackground.top - topMargin: items.mode === "easy" ? 0.2 * categoryBackground.height : '' - } + x: leftScreen.width + middleScreen.width + anchors.top: categoryBackground.top + anchors.topMargin: items.mode === "easy" ? 0.2 * categoryBackground.height : '' Repeater { id: rightZoneRepeater model: rightZone Item { id: rightZoneItem width: middleScreen.width*0.32 height: categoryBackground.height * 0.2 opacity: 1 Zone { id: image source: name } } } - } + } - Rectangle { - id: rightScreen - width: parent.width/3.2 - height: parent.height - anchors { - right: parent.right - bottom: categoryBackground.bottom - top: categoryBackground.top - left: middleScreen.right - } - color: rightAreaContainsDrag ? "#FFCC00" : "green" - opacity: 0.47 + Rectangle { + id: rightScreen + width: parent.width/3 + height: parent.height + x: leftScreen.width + middleScreen.width + color: rightAreaContainsDrag ? "#FFCC00" : "green" + opacity: 0.52 } Rectangle { id: middleScreen - anchors.left: leftZoneModel.right - anchors.right: rightZoneModel.left - color: "#00FFFFFF" width: parent.width/3 height: parent.height + x: leftScreen.width + color: "#00FFFFFF" } Rectangle { id: instructionBox anchors.left: categoryBackground.left anchors.right: categoryimage.left anchors.leftMargin: 0.32 * parent.width anchors.rightMargin: 0.03 * parent.width color: "black" opacity: items.instructionsChecked ? 0.85 : 0 z: 3 radius: 10 border.width: 2 width: horizontalLayout ? parent.width/5 : parent.width/3 height: horizontalLayout ? parent.height/6 : parent.height * 0.09 gradient: Gradient { GradientStop { position: 0.0; color: "#000" } GradientStop { position: 0.9; color: "#666" } GradientStop { position: 1.0; color: "#AAA" } } } Flow { id: options spacing: 0.012 * middleScreen.width anchors { left: leftZoneModel.right right: rightZoneModel.left top: parent.top topMargin: 0.05 * parent.height bottom: categoryBackground.bottom leftMargin: 0.015 * middleScreen.width } Repeater { id: repeater Item { id: item width: middleScreen.width*0.32 height: categoryBackground.height * 0.2 opacity: 1 Zone { id: image source: modelData.src } } } } GCText { id: instructions text: items.details ? items.details[bar.level - 1].instructions : "" visible: items.instructionsChecked anchors.fill: instructionBox anchors.bottom: instructionBox.bottom fontSizeMode: Text.Fit wrapMode: Text.Wrap z: 3 color: "white" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Image { id:categoryimage source: items.details ? items.details[bar.level-1].image : "" width: horizontalLayout ? rightZoneModel.width * 0.35 : rightZoneModel.width * 0.35 height: horizontalLayout ? rightZoneModel.height * 0.18 : rightZoneModel.height * 0.15 y: 0.015*parent.height visible: items.categoryImageChecked anchors { left: middleScreen.right leftMargin: 0.15 * rightZoneModel.width } } BarButton { id: validate source: "qrc:/gcompris/src/core/resource/bar_ok.svg" width: horizontalLayout ? rightZoneModel.width * 0.20 : rightZoneModel.width * 0.35 height: horizontalLayout ? rightZoneModel.width * 0.20 : rightZoneModel.width * 0.35 y: parent.height*0.8 anchors{ rightMargin: 14 * ApplicationInfo.ratio right: parent.right } MouseArea { anchors.fill: parent onClicked: { Activity.allPlaced(); } } } DropArea { id: rightArea anchors.fill: rightZoneModel } DropArea { id: leftArea anchors.fill: leftZoneModel } DialogHelp { id: dialogHelp onClose: home() } Score { id: score fontSize: horizontalLayout ? 0.013 * parent.width : 0.02 * parent.width visible: items.scoreChecked height: horizontalLayout ? 0.1 * parent.height : 0.06 * parent.height width: horizontalLayout ? 0.015 * parent.width : parent.width anchors { top: parent.top right: categoryBackground.right left: categoryimage.right bottom: undefined } } } Keys.onEscapePressed: { Activity.launchMenuScreen(); } Keys.onReleased: { if (event.key === Qt.Key_Back) { event.accepted = true Activity.launchMenuScreen() } } function stop() { if(items.mode == "expert") items.menuScreen.iAmReady.visible = true focus = false rootItem.visible = false } function start() { focus = true rootItem.visible = true } - - function isDragInLeftArea(leftAreaRightBorderPos, elementRightPos) { - if(elementRightPos <= leftAreaRightBorderPos) - return true; - else - return false; - } - function isDragInRightArea(rightAreaLeftBorderPos, elementLeftPos) { - if(elementLeftPos >= rightAreaLeftBorderPos) - return true; - else - return false; - } } diff --git a/src/activities/categorization/Zone.qml b/src/activities/categorization/Zone.qml index 5c729c00a..94b8be91b 100644 --- a/src/activities/categorization/Zone.qml +++ b/src/activities/categorization/Zone.qml @@ -1,88 +1,104 @@ /* GCompris - Zone.qml * * Copyright (C) 2016 Divyam Madaan * * Authors: * Divyam Madaan * * 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 "categorization.js" as Activity Image { id: image width: middleScreen.width*0.28 height: categoryBackground.height * 0.15 source: name MultiPointTouchArea { id: dragArea anchors.fill: parent touchPoints: [ TouchPoint { id: point1 } ] property real positionX property real positionY property real lastX property real lastY property string droppedPosition: "middle" property bool isRight: isRight onPressed: { items.instructionsChecked = false positionX = point1.x positionY = point1.y + } onUpdated: { var moveX = point1.x - positionX var moveY = point1.y - positionY parent.x = parent.x + moveX parent.y = parent.y + moveY - leftAreaContainsDrag = isDragInLeftArea(0, parent.x+parent.width) - rightAreaContainsDrag = isDragInRightArea(rootItem.width/3, parent.x) + var imagePos = image.mapToItem(null,0,0) + leftAreaContainsDrag = isDragInLeftArea(leftScreen.width, imagePos.x + parent.width) + rightAreaContainsDrag = isDragInRightArea(middleScreen.width + leftScreen.width,imagePos.x) lastX = 0, lastY = 0 + + } - onReleased: { + onReleased: { if(lastX == point1.x && lastY == point1.y) return; //Drag.drop(); if(leftAreaContainsDrag) { print("left") - leftZone.append({ "name": image.source.toString() }) + leftZone.append({ "name": image.source.toString(),"droppedZone": "left" }) image.source = "" + leftZoneRepeater.model = leftZone droppedPosition = "left" - activity.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/smudge.wav") } - else if(rightAreaContainsDrag) { + else if(rightAreaContainsDrag) { print("right") - rightZone.append({name: image.source.toString()}) + rightZone.append({"name": image.source.toString(),"droppedZone": right}) image.source = "" - droppedPosition = "right" - activity.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/smudge.wav") + rightZoneRepeater.model = rightZone + droppedPosition = "right" } else { print("middle") droppedPosition = "middle" } leftAreaContainsDrag = false rightAreaContainsDrag = false lastX = point1.x lastY = point1.y } } + function isDragInLeftArea(leftAreaRightBorderPos, elementRightPos) { + if(elementRightPos <= leftAreaRightBorderPos) + return true; + else + return false; + } + function isDragInRightArea(rightAreaLeftBorderPos, elementLeftPos) { + if((rightAreaLeftBorderPos <= elementLeftPos)) + return true; + else + return false; + } } diff --git a/src/activities/categorization/categorization.js b/src/activities/categorization/categorization.js index d7e14b3b6..90f975a64 100644 --- a/src/activities/categorization/categorization.js +++ b/src/activities/categorization/categorization.js @@ -1,269 +1,270 @@ /* GCompris - categorization.js * * Copyright (C) 2016 Divyam Madaan * * Authors: * Divyam Madaan * * 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 . */ .pragma library .import QtQuick 2.0 as Quick .import GCompris 1.0 as GCompris .import "qrc:/gcompris/src/core/core.js" as Core var categoryModelIndex = 0; var currentSubLevel = 0; var items var lessons var categories var images var items var currentLevel = 1 var numberOfLevel var index var categoriesCount var imagesData = [] var categoriesData = [] var boardsUrl function init(items_,boardsUrl_) { boardsUrl = boardsUrl_ items = items_ items.menuModel.clear() currentSubLevel = 0 } function start() { if(items.demoVersion) categoriesCount = 6 else categoriesCount = 18 categoriesData = [] items.categoryReview.stop() var categoriesFilename; for(var i = 1; i <= categoriesCount; i++) { categoriesFilename = boardsUrl + "board" + "/" + "category" + i + "_" + currentSubLevel + ".qml" items.categoryReview.categoryDataset.source = categoriesFilename categoriesData.push(items.categoryReview.categoryDataset.item) } lessons = getAllLessons(categoriesData) categories = getCategoryModel(categoriesData) addPropertiesToCategories(categories) items.menuModel.append(categories) savedPropertiesToCategories(items.dialogActivityConfig.dataToSave) sortByFavorites() items.menuScreen.start() } // Inserts specific properties to the categories function addPropertiesToCategories(categories) { for (var i = 0; i < categories.length; i++) { categories[i]['name'] = categories[i].name categories[i]['image'] = categories[i].image categories[i]['favorite'] = false categories[i]['categoryIndex'] = i } } // Return all the properties we have to save function categoriesToSavedProperties() { var props = {} for(var i = 0; i < items.menuModel.count; i++) { var category = items.menuModel.get(i) props[category.name] = { 'favorite': category['favorite'] } } return props } // Update the categories based on a previous saving function savedPropertiesToCategories(dataToSave) { var props = dataToSave["data"] for(var i = 0; i < items.menuModel.count; i++) { var category = items.menuModel.get(i) var categoryname = category.name if(props && props[category.name]) { category['favorite'] = props[category.name].favorite } else { category['favorite'] = false } } } function sortByFavorites() { for(var i = 0; i < items.menuModel.count; i++) { if(items.menuModel.get(i)['favorite']) { items.menuModel.move(i, 0, 1); } } } function launchMenuScreen() { items.categoryReview.stop() items.menuScreen.start() } function startCategory() { items.categoryReview.start() items.menuScreen.stop() currentLevel = 0 items.bar.level = 0 initLevel() } function storeCategoriesLevels(index_) { index = index_ currentLevel = 0 numberOfLevel = 0 initLevel() } function initLevel() { if(items.mode == "easy") items.instructionsChecked = true else items.instructionsChecked = false items.bar.level = currentLevel + 1 items.categoryReview.score.currentSubLevel = 0; getCategoryLevels(index); numberOfLevel = items.details.length; items.categoryReview.leftZone.clear(); items.categoryReview.rightZone.clear(); items.categoryReview.start(); items.menuScreen.stop() } function nextLevel() { if(numberOfLevel <= ++currentLevel) { currentLevel = 0 } items.categoryReview.score.currentSubLevel = 0 initLevel(index); getCategoryLevels(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(index); getCategoryLevels(); } // Checks if all the items are dragged and dropped in the correct or incorrect area. function allPlaced() { items.categoryReview.score.currentSubLevel = 0; for(var i = 0 ; i < items.categoryReview.repeater.count; ++i) { - var item = items.categoryReview.repeater.itemAt(i); + var item = items.categoryReview.repeater.itemAt(i);print(JSON.stringify(item.isRight)) if((item.droppedPosition === "right" && item.isRight) || (item.droppedPosition === "left" && !item.isRight)) { + items.categoryReview.score.currentSubLevel ++; } } if(items.categoryReview.score.currentSubLevel == items.categoryReview.repeater.count) { items.bonus.good("flower"); } else { items.bonus.bad("flower"); } } // Save properties to lessons function getCategoryLevels() { var randomGood = 0; var randomBad = 0; /* If easy or medium mode is selected, store the details of levels of category of that respective index in items.details. */ if(items.mode !== "expert") { items.details = lessons[index].map(function(ele) { return { "tags": ele.tags , "instructions": ele.instructions, "image": ele.image, "numberOfGood": ele.maxNumberOfGood, "numberofBad": ele.maxNumberOfBad, "categoryImages": ele.levelImages ,"prefix": ele.prefix } }); } // If expert mode is selected, select a random level (selectedLevel) from a random category (selectedCategory) else if(items.mode === "expert") { var selectedCategory = Math.floor(Math.random() * lessons.length) var selectedLevel = [] selectedLevel[0] = lessons[selectedCategory][Math.floor(Math.random() * lessons[selectedCategory].length)] items.details = selectedLevel.map(function(ele) { return { "tags": ele.tags , "instructions": ele.instructions, "image": ele.image, "numberOfGood": ele.maxNumberOfGood, "numberofBad": ele.maxNumberOfBad, "categoryImages": ele.levelImages ,"prefix": ele.prefix } }); } // imagesPrefix stores the prefix of images in categoryx_0.qml var imagesPrefix = items.details[items.bar.level - 1].prefix var imagesDetails = {} // Adds prefix to the image paths stored in items.details Object.keys(items.details[items.bar.level - 1].categoryImages[0]).map(function (k) { imagesDetails[imagesPrefix + k] = items.details[items.bar.level - 1].categoryImages[0][k]; }); // keys contains all the image paths. The good images are then filtered on the basis of the categoryTag var keys = Object.keys(imagesDetails); var categoryTag = items.details[items.bar.level - 1].tags; var result = keys.filter(function(element) { var bool = imagesDetails[element].every(function (ele) { return categoryTag.indexOf(ele) < 0; }); return !bool; }); // good set of images var goodvalidimages = result.length; var numberOfGood = Math.min(goodvalidimages,items.details[items.bar.level-1].numberOfGood); var table = result.map(function(obj) { return {"src": obj, "isRight": true} }); table = table.splice(0,numberOfGood); // remaining bad set of images filtered and stored var resultBad = keys.filter(function(i) {return result.indexOf(i) < 0;}); var tableBad = resultBad.map(function(obj) { return {"src": obj, "isRight": false} }); var badvalidimages = resultBad.length; var numberofBad = Math.min(badvalidimages,items.details[items.bar.level-1].numberofBad); tableBad =tableBad.splice(0,numberofBad); // Concat both the good and bad images, shuffles them and stores them in the repeater model table = table.concat(tableBad); Core.shuffle(table); items.categoryReview.repeater.model = table items.categoryReview.score.numberOfSubLevels = items.categoryReview.repeater.count } // get categories details from the complete dataset function getCategoryModel(dataset) { var categories = [] for (var c = 0; c < dataset.length; c++) { categories.push({ 'name': dataset[c].levels[0].name, 'image': dataset[c].levels[0].image, 'index': c }) } return categories } // get all the content (levels) from the category in dataset function getAllLessons(dataset){ var lessons = [] for(var c = 0; c < dataset.length; c++) { lessons.push(dataset[c].levels[0].content) } return lessons }