diff --git a/src/activities/traffic/ActivityConfig.qml b/src/activities/traffic/ActivityConfig.qml new file mode 100644 index 000000000..6a6401c50 --- /dev/null +++ b/src/activities/traffic/ActivityConfig.qml @@ -0,0 +1,60 @@ +/* GCompris - ActivityConfig.qml + * + * Copyright (C) 2019 Johnny Jazeix + * + * Authors: + * Johnny Jazeix + * + * 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 "../../core" + +Item { + id: activityConfiguration + property Item background + property alias modeBox: modeBox + property var availableModes: [ + { "text": qsTr("Colors"), "value": "COLOR" }, + { "text": qsTr("Images"), "value": "IMAGE" } + ] + Flow { + id: flow + spacing: 5 + width: parent.width + GCComboBox { + id: modeBox + model: availableModes + background: activityConfiguration.background + label: qsTr("Select your mode") + } + } + + property var dataToSave + + function setDefaultValues() { + for(var i = 0 ; i < availableModes.length ; i ++) { + if(availableModes[i].value === dataToSave["mode"]) { + modeBox.currentIndex = i; + break; + } + } + } + + function saveValues() { + var newMode = availableModes[modeBox.currentIndex].value; + dataToSave = {"mode": newMode}; + } +} diff --git a/src/activities/traffic/Traffic.qml b/src/activities/traffic/Traffic.qml index 000cc7d87..a90e0fea1 100644 --- a/src/activities/traffic/Traffic.qml +++ b/src/activities/traffic/Traffic.qml @@ -1,191 +1,159 @@ /* GCompris - Traffic.qml * * Copyright (C) 2014 Holger Kaelberer * * Authors: * Bruno Coudoin (GTK+ version) * Holger Kaelberer (Qt Quick port) * * 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 "traffic.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Image { id: background source: "qrc:/gcompris/src/activities/traffic/resource/traffic_bg.svg" sourceSize.width: Math.max(parent.width, parent.height) fillMode: Image.PreserveAspectCrop signal start signal stop property string mode: "IMAGE" // allow to choose between "COLOR" and "IMAGE" // mode, candidate for a config dialog Component.onCompleted: { - dialogActivityConfig.getInitialConfiguration() + dialogActivityConfig.initialize() activity.start.connect(start) activity.stop.connect(stop) } QtObject { id: items property Item main: activity.main property GCSfx audioEffects: activity.audioEffects property alias background: background property alias bar: bar property alias bonus: bonus property alias score: score property alias jamBox: jamBox property alias jamGrid: jamGrid } onStart: { Activity.start(items, mode) } onStop: { Activity.stop() } Image { id: jamBox source: "qrc:/gcompris/src/activities/traffic/resource/traffic_box.svg" anchors.centerIn: parent sourceSize.width: Math.min(background.width * 0.85, background.height * 0.85) fillMode: Image.PreserveAspectFit property double scaleFactor: background.width / background.sourceSize.width Grid { id: jamGrid anchors.centerIn: parent width: parent.width - 86 * jamBox.scaleFactor * ApplicationInfo.ratio height: parent.height - 86 * jamBox.scaleFactor * ApplicationInfo.ratio columns: 6 rows: 6 spacing: 0 // Add an alias to mode so it can be used on Car items property alias mode: background.mode Repeater { id: gridRepeater model: jamGrid.columns * jamGrid.rows delegate: Rectangle { id: gridDelegate height: jamGrid.height/ jamGrid.rows width: height border.width: 1 border.color: "white" color: "#444444" } } } } DialogHelp { id: dialogHelp onClose: home() } - - DialogActivityConfig { - id: dialogActivityConfig - currentActivity: activity - content: Component { - Item { - property alias modeBox: modeBox - property var availableModes: [ - { "text": qsTr("Colors"), "value": "COLOR" }, - { "text": qsTr("Images"), "value": "IMAGE" } - ] + DialogChooseLevel { + id: dialogActivityConfig + currentActivity: activity.activityInfo - Flow { - id: flow - spacing: 5 - width: dialogActivityConfig.width - GCComboBox { - id: modeBox - model: availableModes - background: dialogActivityConfig - label: qsTr("Select your mode") - } - } - } + onClose: { + home() } - onClose: home() - onLoadData: { - if(dataToSave && dataToSave["mode"]) { - mode = dataToSave["mode"]; - Activity.mode = dataToSave["mode"]; - } - } - onSaveData: { - mode = dialogActivityConfig.configItem.availableModes[dialogActivityConfig.configItem.modeBox.currentIndex].value; - dataToSave = {"mode": mode} - Activity.mode = mode; + levelFolder = dialogActivityConfig.chosenLevel + currentActivity.currentLevel = dialogActivityConfig.chosenLevel + ApplicationSettings.setCurrentLevel(currentActivity.name, dialogActivityConfig.chosenLevel) + home() } - - function setDefaultValues() { - for(var i = 0 ; i < dialogActivityConfig.configItem.availableModes.length ; i ++) { - if(dialogActivityConfig.configItem.availableModes[i].value === mode) { - dialogActivityConfig.configItem.modeBox.currentIndex = i; - break; - } + onLoadData: { + if(activityData && activityData["mode"]) { + background.mode = activityData["mode"]; } } } Bar { id: bar - content: BarEnumContent { value: help | home | level | reload | config } + content: BarEnumContent { value: help | home | level | reload | activityConfig } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.initLevel() - onConfigClicked: { - dialogActivityConfig.active = true - // Set default values - dialogActivityConfig.setDefaultValues(); + onActivityConfigClicked: { displayDialog(dialogActivityConfig) } } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextSubLevel) } Score { id: score anchors.top: parent.top anchors.topMargin: 10 * ApplicationInfo.ratio anchors.right: parent.right anchors.rightMargin: 10 * ApplicationInfo.ratio anchors.bottom: undefined } } } diff --git a/src/core/DialogChooseLevel.qml b/src/core/DialogChooseLevel.qml index dc24c89c4..135c0525a 100644 --- a/src/core/DialogChooseLevel.qml +++ b/src/core/DialogChooseLevel.qml @@ -1,353 +1,359 @@ /* GCompris - DialogChooseLevel.qml * * Copyright (C) 2018 Johnny Jazeix * * Authors: * Johnny Jazeix * * 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 QtQuick.Controls 1.5 import GCompris 1.0 /** * todo * @ingroup components * * todo * * @sa ApplicationSettings * @inherit QtQuick.Item */ Rectangle { id: dialogChooseLevel visible: false /* Public interface: */ /** * type:string * The name of the activity in case of per-activity config. * * Will be autogenerated unless set by the caller. */ property string activityName /// @cond INTERNAL_DOCS property bool isDialog: true /** * type:string * Title of the configuration dialog. */ readonly property string title: currentActivity ? qsTr("%1 settings").arg(currentActivity.title) : "" property var difficultiesModel: [] property QtObject currentActivity property string chosenLevel property var activityData onActivityDataChanged: loadData() /// @endcond /** * Emitted when the config dialog has been closed. */ signal close /** * Emitted when the config dialog has been started. */ signal start onStart: initialize() signal stop /** * Emitted when the settings are to be saved. * * The actual persisting of the settings in the settings file is done by * DialogActivityConfig. The activity has to take care to update its * internal state. */ signal saveData signal startActivity /** * Emitted when the config settings have been loaded. */ signal loadData color: "#696da3" border.color: "black" border.width: 1 function initialize() { activityName = currentActivity.name.split('/')[0] // dataset information chosenLevel = currentActivity.currentLevel difficultiesModel = [] - for(var level in currentActivity.levels) { - objectiveLoader.dataFiles.push({"level": currentActivity.levels[level], "file": "qrc:/gcompris/src/activities/"+activityName+"/resource/"+currentActivity.levels[level]+"/Data.qml"}) + if(currentActivity.levels.length == 0) { + print("no levels to load for", activityName) + } + else { + for(var level in currentActivity.levels) { + objectiveLoader.dataFiles.push({"level": currentActivity.levels[level], "file": "qrc:/gcompris/src/activities/"+activityName+"/resource/"+currentActivity.levels[level]+"/Data.qml"}) + } + objectiveLoader.start() } - objectiveLoader.start() } Loader { id: objectiveLoader property var dataFiles: [] property var currentFile signal start signal stop onStart: { + if(dataFiles.length) var file = dataFiles.shift() currentFile = file source = file.file.toString() } onLoaded: { difficultiesModel.push({"level": currentFile.level, "objective": item.objective, "difficulty": item.difficulty}) if(dataFiles.length != 0) { start() } else { stop() } } onStop: { difficultiesRepeater.model = difficultiesModel } } Row { visible: true spacing: 2 Item { width: 10; height: 1 } Column { spacing: 10 anchors.top: parent.top Item { width: 1; height: 10 } Rectangle { color: "#e6e6e6" radius: 6.0 width: dialogChooseLevel.width - 30 height: title.height * 1.2 border.color: "black" border.width: 2 Row { spacing: 2 padding: 8 Image { id: titleIcon anchors { left: parent.left top: parent.top margins: 4 * ApplicationInfo.ratio } } GCText { id: title text: dialogChooseLevel.title width: dialogChooseLevel.width - (30 + cancel.width) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: "black" fontSize: 20 font.weight: Font.DemiBold wrapMode: Text.WordWrap } } } // Header buttons Row { id: datasetOptionsRow height: datasetVisibleButton.height width: parent.width spacing: parent.width / 4 anchors.leftMargin: parent.width / 8 Button { id: datasetVisibleButton text: qsTr("Dataset") enabled: difficultiesRepeater.count != 0 width: parent.width / 3 property bool selected: true style: GCButtonStyle { selected: datasetVisibleButton.selected } onClicked: { selected = true; } } Button { id: optionsVisibleButton text: qsTr("Options") enabled: activityConfigFile.exists("qrc:/gcompris/src/activities/"+activityName+"/ActivityConfig.qml") width: parent.width / 3 style: GCButtonStyle { selected: !datasetVisibleButton.selected } onClicked: { datasetVisibleButton.selected = false; } //showOptions() } } // "Dataset"/"Options" content Rectangle { color: "#e6e6e6" radius: 6.0 width: dialogChooseLevel.width - 30 height: dialogChooseLevel.height - (30 + title.height * 1.2) - saveAndPlayRow.height - datasetOptionsRow.height - 3 * parent.spacing border.color: "black" border.width: 2 Flickable { id: flick anchors.margins: 8 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom flickableDirection: Flickable.VerticalFlick clip: true contentHeight: contentItem.childrenRect.height + 40 * ApplicationInfo.ratio Loader { id: configLoader visible: !datasetVisibleButton.selected active: optionsVisibleButton.enabled source: active ? "qrc:/gcompris/src/activities/"+activityName+"/ActivityConfig.qml" : "" onItemChanged: { if(item) { item.background = dialogChooseLevel dialogChooseLevel.saveData.connect(save) getInitialConfiguration() } } function getInitialConfiguration() { activityData = Qt.binding(function() { return item.dataToSave }) if(item) { item.dataToSave = ApplicationSettings.loadActivityConfiguration(activityName) item.setDefaultValues() } } function save() { item.saveValues() ApplicationSettings.saveActivityConfiguration(activityName, item.dataToSave) } } Column { visible: datasetVisibleButton.selected spacing: 10 ExclusiveGroup { id: levelsGroup } Repeater { id: difficultiesRepeater delegate: Row { height: objective.height Image { id: difficultyIcon source: "qrc:/gcompris/src/core/resource/difficulty" + modelData.difficulty + ".svg"; sourceSize.height: objective.indicatorImageHeight anchors.verticalCenter: objective.verticalCenter } GCDialogCheckBox { id: objective width: dialogChooseLevel.width - 30 - difficultyIcon.width - 2 * flick.anchors.margins text: modelData.objective exclusiveGroup: levelsGroup checked: chosenLevel === modelData.level onClicked: chosenLevel = modelData.level } } } } } // The scroll buttons GCButtonScroll { anchors.right: parent.right anchors.rightMargin: 5 * ApplicationInfo.ratio anchors.bottom: flick.bottom anchors.bottomMargin: 5 * ApplicationInfo.ratio onUp: flick.flick(0, 1400) onDown: flick.flick(0, -1400) upVisible: flick.visibleArea.yPosition <= 0 ? false : true downVisible: flick.visibleArea.yPosition + flick.visibleArea.heightRatio >= 1 ? false : true } } // Footer buttons Row { id: saveAndPlayRow height: cancelButton.height width: parent.width spacing: parent.width / 16 Button { id: cancelButton text: qsTr("Cancel") width: parent.width / 4 property bool selected: true style: GCButtonStyle {} onClicked: dialogChooseLevel.close() } Button { id: saveButton text: qsTr("Save") width: parent.width / 4 property bool selected: true style: GCButtonStyle { } onClicked: { saveData(); } } Button { id: saveAndStartButton text: qsTr("Save and start") width: parent.width / 3 style: GCButtonStyle { } onClicked: { saveData(); startActivity(); } } } Item { width: 1; height: 10 } } } // The cancel button GCButtonCancel { id: cancel onClose: { parent.close() } } File { id: activityConfigFile } }