Commit 3b23c7aa authored by Holger Kaelberer's avatar Holger Kaelberer
Browse files

balancebox: rework editor integration (2)

- Factor out more stuff from balanacebox.js to common

- Add configuration dialog.

- Access editor through configuration dialog. Testing still can happen
directly in the Balancebox qml scene.

- Therefore, to switch views well between editor and balancebox (for
testing) extend the page stack and allow to push+pop > 1 views.
parent c61f77aa
......@@ -6,12 +6,12 @@ ActivityInfo {
icon: "balancebox/balancebox.svg"
author: "Holger Kaelberer <holger.k@elberer.de>"
demo: true
title: qsTr("Keep the balance")
description: qsTr("Practice fine grained movements, balancing a ball/")
title: qsTr("Balance Box")
description: qsTr("Practice fine grained movements, balancing the ball by tilting the box.")
// intro: "Click on the word matching the picture."
goal: qsTr("")
prerequisite: "None"
manual: qsTr("Navigate the ball to the goal without making it fall into the holes.")
manual: qsTr("Navigate the ball to the goal without making it fall into the holes. Numbered contact buttons in the box need to be touched in the correct order to unlock the door.")
credit: ""
section: "computer keyboard mobile"
}
......@@ -34,7 +34,8 @@ import "balancebox.js" as Activity
ActivityBase {
id: activity
property string mode: "play" // play or test
property string mode: "play" // "play" or "test"
property string levelSet: "builtin" // "builtin" or "user"
property var testLevel
onStart: {
......@@ -74,23 +75,14 @@ ActivityBase {
function startEditor() {
console.log("XXX: launching editor");
editorLoader.active = true;
displayDialog(editorLoader.item);
}
Button {
id: editButton
anchors.top: parent.top
anchors.right: parent.right
width: 80
height: 30
text: "Editor"
onClicked: {
//console.log("XXX mode=" + activity.mode);
startEditor();
}
if (activity.mode == "test")
displayDialogs([dialogActivityConfig, editorLoader.item]);
else
displayDialog(editorLoader.item);
}
Component.onCompleted: {
dialogActivityConfig.getInitialConfiguration()
activity.start.connect(start)
activity.stop.connect(stop)
items.dpi = Math.round(Screen.pixelDensity*25.4);
......@@ -104,6 +96,7 @@ ActivityBase {
QtObject {
id: items
property string mode: activity.mode
property string levelSet: activity.levelSet
property var testLevel: activity.testLevel
property Item main: activity.main
property alias background: background
......@@ -361,7 +354,9 @@ ActivityBase {
Bar {
id: bar
content: BarEnumContent {
value: activity.mode == "play" ? (help | home | level) : ( help | home )
value: activity.mode == "play"
? (help | home | level | config )
: ( help | home )
}
onHelpClicked: {
displayDialog(dialogHelp)
......@@ -374,6 +369,12 @@ ActivityBase {
else
activity.home()
}
onConfigClicked: {
dialogActivityConfig.active = true
// Set default values
dialogActivityConfig.setDefaultValues();
displayDialog(dialogActivityConfig)
}
}
Bonus {
......@@ -391,5 +392,71 @@ ActivityBase {
repeat: false
onTriggered: Activity.keyboardHandler()
}
DialogActivityConfig {
id: dialogActivityConfig
currentActivity: activity
content: Component {
Item {
property alias levelsBox: levelsBox
property var availableLevels: [
{ "text": qsTr("Bultin"), "value": "builtin" },
{ "text": qsTr("User"), "value": "user" },
]
Flow {
id: flow
spacing: 5
width: dialogActivityConfig.width
GCComboBox {
id: levelsBox
model: availableLevels
background: dialogActivityConfig
label: qsTr("Select your level set")
}
Button {
id: editorButton
style: GCButtonStyle {}
//width: 80
height: levelsBox.height
text: "Start Editor"
visible: levelsBox.currentIndex == 1
onClicked: background.startEditor()
}
}
}
}
onClose: home()
onLoadData: {
if(dataToSave && dataToSave["levels"]) {
activity.levelSet = dataToSave["levels"];
}
}
onSaveData: {
var newLevels = dialogActivityConfig.configItem
.availableLevels[dialogActivityConfig.configItem.levelsBox.currentIndex].value;
if (newLevels !== activity.levelSet) {
activity.levelSet = newLevels;
dataToSave = {"levels": activity.levelSet};
//activity.start(); done automatically during view switch
}
}
function setDefaultValues() {
for(var i = 0 ;
i < dialogActivityConfig.configItem.availableLevels.length;
i ++) {
if(dialogActivityConfig.configItem.availableLevels[i].value === activity.levelSet) {
dialogActivityConfig.configItem.levelsBox.currentIndex = i;
break;
}
}
}
}
}
}
......@@ -30,43 +30,7 @@
.import GCompris 1.0 as GCompris
.import Box2D 2.0 as Box2D
/**
* Level description format:
*
* Example:
* [ { "level": 1,
* "map": [ [ 0x0000, 0x0308, ... ],
* [ 0x0010, 0x0008, ... ],
* ...
* ],
* "targets": [ 1, 2, 3, 5, 10, ... ]
* },
* { "level": 2, ... }
* ...
* ]
*
* "level": Number of the level.
* "map": Definition of the map inside the balancebox.
* The map is a 2-dimensional array of map cells. A cell is
* described by a bitmask of 16 bit with the lower 8bit defining walls,
* objects, etc. (cf. below) and the higher 8 bit defining the order of
* buttons present on the map. The values of the buttons are described
* in the "targets" property.
* "targets": Values of the buttons present on the map. Most likely these will
* be numbers, but letters are also possible. The order in which they
* need to be pressed by the ball is defined in the higher 8 bits of
* the map fields.
*/
var EMPTY = 0x0000;
var NORTH = 0x0001;
var EAST = 0x0002;
var SOUTH = 0x0004;
var WEST = 0x0008;
// all the following are mutually exclusive:
var START = 0x0010;
var GOAL = 0x0020;
var HOLE = 0x0040;
var CONTACT = 0x0080;
Qt.include("balancebox_common.js")
var dataset = null;
......@@ -95,8 +59,6 @@ var debugDraw = false;
var currentLevel = 0;
var numberOfLevel = 0;
var items;
var baseUrl = "qrc:/gcompris/src/activities/balancebox/resource";
var levelsFile = baseUrl + "/levels-default.json";
var level;
var map; // current map
......@@ -112,7 +74,6 @@ var wallComponent = Qt.createComponent("qrc:/gcompris/src/activities/balancebox/
var contactComponent = Qt.createComponent("qrc:/gcompris/src/activities/balancebox/BalanceContact.qml");
var balanceItemComponent = Qt.createComponent("qrc:/gcompris/src/activities/balancebox/BalanceItem.qml");
var contactIndex = -1;
var userFile = GCompris.ApplicationInfo.getWritablePath() + "/balancebox/" + "levels-user.json"
function start(items_) {
items = items_;
......@@ -145,8 +106,9 @@ function start(items_) {
* 14: SCREEN_ORIENTATION_LOCKED: inverted rotation on tablet
*/
}
var levelsFile = builtinFile;
if (items.levelSet == "user")
levelsFile = userFile;
dataset = items.parser.parseFromUrl(levelsFile, validateLevels);
if (dataset == null) {
console.error("Balancebox: Error loading levels from " + levelsFile
......@@ -369,7 +331,7 @@ function initMap()
}
}
}
if (goalUnlocked) // if we have no contacts at all
if (goalUnlocked && goal) // if we have no contacts at all
goal.imageSource = baseUrl + "/door.svg";
}
......
......@@ -18,6 +18,35 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
* Level description format:
*
* Example:
* [ { "level": 1,
* "map": [ [ 0x0000, 0x0308, ... ],
* [ 0x0010, 0x0008, ... ],
* ...
* ],
* "targets": [ 1, 2, 3, 5, 10, ... ]
* },
* { "level": 2, ... }
* ...
* ]
*
* "level": Number of the level.
* "map": Definition of the map inside the balancebox.
* The map is a 2-dimensional array of map cells. A cell is
* described by a bitmask of 16 bit with the lower 8bit defining walls,
* objects, etc. (cf. below) and the higher 8 bit defining the order of
* buttons present on the map. The values of the buttons are described
* in the "targets" property.
* "targets": Values of the buttons present on the map. Most likely these will
* be numbers, but letters are also possible. The order in which they
* need to be pressed by the ball is defined in the higher 8 bits of
* the map fields.
*/
var EMPTY = 0x0000;
var NORTH = 0x0001;
var EAST = 0x0002;
......@@ -30,6 +59,9 @@ var HOLE = 0x0040;
var CONTACT = 0x0080;
var baseUrl = "qrc:/gcompris/src/activities/balancebox/resource";
var builtinFile = baseUrl + "/levels-default.json";
var userFile = "file://" + GCompris.ApplicationInfo.getWritablePath()
+ "/balancebox/" + "levels-user.json"
function validateLevels(doc)
{
......
......@@ -77,7 +77,7 @@ Item {
}
onStop: {console.log("XXX Editor onStop");}
Component.onCompleted: console.log("XXX editor complete");
Component.onCompleted: console.log("XXX editor complete " + filename);
QtObject {
id: props
......@@ -106,8 +106,9 @@ Item {
editor.isTesting = true;
testBox.mode = "test";
testBox.testLevel = Activity.modelToLevel();
testBox.start();
activity.home();
//testBox.start();
//activity.home();
back(testBox);
}
function stopTesting() {
......
......@@ -33,8 +33,7 @@ var TOOL_HOLE = HOLE
var TOOL_CONTACT = CONTACT
var TOOL_GOAL = GOAL
var TOOL_BALL = START
var userFile = "file://" + GCompris.ApplicationInfo.getWritablePath()
+ "/balancebox/" + "levels-user.json"
var levels;
var level;
var currentLevel;
......@@ -52,7 +51,7 @@ function initEditor(_props)
numberOfLevel = 0;
props.lastBallIndex = -1;
props.lastGoalIndex = -1;
console.log("XXX loaded levels form file " + props.editor.filename);
levels = [];
if (props.file.exists(props.editor.filename)) {
levels = props.parser.parseFromUrl(props.editor.filename, validateLevels);
......@@ -60,7 +59,8 @@ function initEditor(_props)
console.error("BalanceboxEditor: Error loading levels from "
+ props.editor.filename);
levels = []; // restart with an empty level-set
}
} else
console.log("XXX loaded levels form file " + props.editor.filename);
}
numberOfLevel = levels.length;
......@@ -86,6 +86,7 @@ function createEmptyLevel()
function initLevel()
{
console.log("XXX editor initLevel levels=" + JSON.stringify(levels));
if (currentLevel >= numberOfLevel) {
levels.push(createEmptyLevel());
numberOfLevel++;
......
......@@ -46,6 +46,14 @@ ActivityBase {
focus: true
activityInfo: ActivityInfoTree.rootMenu
onBack: {
console.log("XXX onBack to " + to);
pageView.pop(to);
// Restore focus that has been taken by the loaded activity
if(pageView.currentItem == menuActivity)
focus = true;
}
onHome: {
if(pageView.depth === 1) {
Core.quit(main);
......@@ -60,6 +68,16 @@ ActivityBase {
onDisplayDialog: pageView.push(dialog)
onDisplayDialogs: {
console.log("XXX onForward to " + dialogs);
var toPush = new Array();
for (var i = 0; i < dialogs.length; i++) {
displayDialog(dialogs[i]);
toPush.push({item: dialogs[i]});
}
pageView.push(toPush);
}
// @cond INTERNAL_DOCS
property string url: "qrc:/gcompris/src/activities/menu/resource/"
property variant sections: [
......
......@@ -118,6 +118,12 @@ Item {
*/
signal home
/**
* Emitted when the user wants to return several views back in the
* page stack.
*/
signal back(Item to)
/**
* Emitted every time the activity has been started.
*
......@@ -142,8 +148,21 @@ Item {
*/
signal displayDialog(Item dialog)
/**
* Emitted when multiple @p dialogs should be pushed on the page-stack
*
* Emit this signal when you want to stack >1 views. The last one will be
* shown the intermediated ones will be kept on the page stack for later
* pop() calls.
*
* @param dialogs Array of dialogs to push;
*/
signal displayDialogs(var dialogs)
onBack: menu ? menu.back(to) : ""
onHome: menu ? menu.home() : ""
onDisplayDialog: menu ? menu.displayDialog(dialog) : ""
onDisplayDialogs: menu ? menu.displayDialogs(dialogs) : ""
Keys.forwardTo: activity.children
Keys.onEscapePressed: {console.log("XXX: Base onEscape"); home();}
......
......@@ -157,13 +157,16 @@ Window {
id: root
function getTransition(properties)
{
console.log("XXX getTransition: exitItem=" + properties.exitItem + " enterItem=" + properties.enterItem);
audioVoices.clearQueue()
if(!properties.exitItem.isDialog) {
if(!properties.enterItem.isDialog) {
playIntroVoice(properties.enterItem.activityInfo.name)
}
properties.enterItem.start()
//properties.enterItem.start() // hkaelber // moved outside of if for configDialog -> Editor transition in balancebox
}
if (properties.enterItem.start)
properties.enterItem.start();
if(properties.name === "pushTransition") {
if(properties.enterItem.isDialog) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment