diff --git a/src/activities/crane/Crane.qml b/src/activities/crane/Crane.qml old mode 100755 new mode 100644 index 1e0633a92..5bd99aa66 --- a/src/activities/crane/Crane.qml +++ b/src/activities/crane/Crane.qml @@ -1,468 +1,472 @@ /* GCompris - Crane.qml * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (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.1 import "../../core" import "crane.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent color: "#ffeecc" signal start signal stop Component.onCompleted: { 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 board: board property alias grid: grid property alias repeater: repeater property alias modelRepeater: modelRepeater property alias gridRepeater: gridRepeater property alias showGrid1: showGrid1 property int selected property int columns property int rows property bool ok: true property int sensivity: 80 property bool gameFinished: false } onStart: { Activity.start(items) } onStop: { Activity.stop() } property bool portrait: height > width ? true : false Keys.onPressed: { if (event.key === Qt.Key_Left) Activity.move("left") else if (event.key === Qt.Key_Right) Activity.move("right") else if (event.key === Qt.Key_Up) Activity.move("up") else if (event.key === Qt.Key_Down) Activity.move("down") else if (event.key === Qt.Key_Space || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Return) Activity.move("next") } //implementation of Swipe effect MouseArea { anchors.fill: parent property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) } Rectangle { id: board color: "lightblue" radius: width * 0.02 z: 1 anchors { verticalCenter: crane_vertical.verticalCenter right: crane_vertical.left margins: 15 } width: background.portrait ? parent.width * 0.65 : ((parent.width - anchors.margins * 3 - crane_vertical.width) / 2 ) * 0.9 height: background.portrait ? (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height ) / 2 : (parent.height - bar.height * 1.45 - crane_top.height - crane_body.height) * 0.9 } Grid { id: showGrid1 columns: items.columns rows: items.rows z: 1 anchors.fill: board Repeater { id: gridRepeater Rectangle { width: board.width/items.columns height: board.height/items.rows color: "transparent" border.width: 2 border.color: "grey" } } } Rectangle { id: coverEgdes1 color: "transparent" width: board.width height: board.height border.color: board.color border.width: 10 opacity: showGrid1.opacity anchors.centerIn: board z: 3 } Grid { id: grid columns: items.columns rows: items.rows z: 4 anchors.fill: board Repeater { id: repeater Image { id: figure sourceSize.height: board.height/3 sourceSize.width: board.width/3 width: board.width/items.columns height: board.height/items.rows + property int initialIndex: -1 + property bool showSelected: false property alias selected: selected property alias anim: anim property alias opac: selected.opacity property int distance property int indexChange property int startPoint property string animationProperty property int _index: index // make current index accessible from outside SequentialAnimation { id: anim PropertyAction { target: items; property: "ok"; value: "false"} NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint; to: figure.startPoint + distance; duration: 200 } PropertyAction { target: figure; property: "opacity"; value: 0 } PropertyAction { target: selected; property: "opacity"; value: 0 } NumberAnimation { target: figure; property: figure.animationProperty; from: figure.startPoint + distance; to: figure.startPoint; duration: 0; } PropertyAction { target: figure; property: "opacity"; value: 1 } PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "source"; value: figure.source } PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "opac"; value: 1 } + + PropertyAction { target: items.repeater.itemAt(items.selected + indexChange); property: "initialIndex"; value: figure.initialIndex } + PropertyAction { target: figure; property: "initialIndex"; value: -1 } + PropertyAction { target: figure; property: "source"; value: "" } PropertyAction { target: items; property: "ok"; value: "true"} ScriptAction { script: Activity.checkAnswer() } } MouseArea { anchors.fill: parent // Swipe effect property int startX; property int startY; onPressed: { startX = mouse.x; startY = mouse.y; print("print: ",Activity.showGrid[Activity.currentLevel]=="true" ) } onReleased: Activity.gesture(mouse.x - startX, mouse.y - startY) // Select a figure with mouse/touch onClicked: { if (source != "") { items.repeater.itemAt(items.selected).opac = 0 items.selected = index items.repeater.itemAt(items.selected).opac = 1 } } } // selected marker Image { id: selected source: "resource/selected.png" width: parent.width height: parent.height opacity: 0 } } } } Rectangle { id: modelBoard color: "pink" radius: width * 0.02 z: 1 anchors { left: background.portrait ? board.left : crane_vertical.right top: background.portrait ? crane_body.bottom : parent.top topMargin: background.portrait ? board.anchors.margins : crane_top.height * 1.5 margins: board.anchors.margins } width: board.width height: board.height } Grid { id: modelGrid columns: items.columns rows: items.rows anchors.fill: modelBoard z: 4 Repeater { id: modelRepeater Image { id: modelFigure sourceSize.height: board.height/items.rows sourceSize.width: board.width/items.columns width: board.width/items.columns height: board.height/items.rows } } } Grid { id: showGrid2 columns: items.columns rows: items.rows z: 1 opacity: showGrid1.opacity anchors.fill: modelBoard Repeater { id: gridRepeater2 model: gridRepeater.model Rectangle { width: modelBoard.width/items.columns height: modelBoard.height/items.rows color: "transparent" border.width: 2 border.color: Activity.showGrid[Activity.currentLevel] ? "grey" : "transparent" } } } Rectangle { id: coverEgdes2 color: "transparent" width: modelBoard.width height: modelBoard.height - border.color: Activity.showGrid[Activity.currentLevel] ? modelBoard.color : transparent + border.color: Activity.showGrid[Activity.currentLevel] ? modelBoard.color : "transparent" border.width: 10 anchors.centerIn: modelBoard opacity: showGrid1.opacity z: 3 } Image { id: crane_top source: "resource/crane_up.svg" sourceSize.width: background.portrait ? background.width * 0.8 : background.width * 0.5 sourceSize.height: background.portrait ? background.height * 0.03 : background.height * 0.06 width: background.portrait ? background.width * 0.8 : background.width * 0.5 height: background.portrait ? background.height * 0.03 : background.height * 0.06 z: 4 anchors { top: parent.top right: crane_vertical.right rightMargin: 0 margins: board.anchors.margins } } Image { id: crane_vertical source: "resource/crane_vertical.svg" sourceSize.width: background.width * 0.04 sourceSize.height: background.height * 0.73 width: background.width * 0.05 height: background.portrait ? background.height * 0.45 : background.height * 0.73 anchors { top: crane_top.top right: background.portrait ? parent.right : parent.horizontalCenter rightMargin: background.portrait ? width / 2 : - width / 2 topMargin: board.anchors.margins } } Image { id: crane_body source: "resource/crane_only.svg" z: 2 sourceSize.width: parent.width / 5 sourceSize.height: parent.height/ 3.6 mirror: background.portrait ? true : false anchors { top: crane_vertical.bottom topMargin: - (height / 1.8) right: crane_vertical.right rightMargin: background.portrait ? board.anchors.margins : - crane_body.width + crane_vertical.width margins: board.anchors.margins } } Image { id: crane_wire source: "resource/crane-wire.svg" z: 1 sourceSize.width: parent.width / 22 sourceSize.height: parent.width / 17 anchors { right: crane_body.left bottom: crane_command.verticalCenter rightMargin: -10 bottomMargin: -10 } } Image { id: crane_command source: "resource/command.svg" sourceSize.width: parent.width / 4 sourceSize.height: parent.height/ 3.5 mirror: true anchors { top: crane_body.top bottom: crane_body.bottom right: crane_wire.left rightMargin: 0 topMargin: background.portrait ? board.anchors.margins : 50 margins: board.anchors.margins } Controls { id: up source: "resource/arrow_up.svg" anchors { left: parent.left leftMargin: parent.width / 10 } command: "up" } Controls { id: down source: "resource/arrow_down.svg" anchors { left: up.right leftMargin: parent.width / 20 } command: "down" } Controls { id: left source: "resource/arrow_left.svg" anchors { right: right.left rightMargin: parent.width / 20 } command: "left" } Controls { id: right source: "resource/arrow_right.svg" anchors { right: parent.right rightMargin: parent.width / 10 } command: "right" } } Rectangle { id: cable color: "black" width: 5 - height: convert.y - x: convert.x + items.repeater.itemAt(items.selected).width / 2 + height: convert.y - crane_top.y + x: convert.x + board.width / items.columns / 2 z: 3 anchors.top: crane_top.top anchors.topMargin: 10 - property var convert: items.repeater.mapToItem(background,items.repeater.itemAt(items.selected).x,items.repeater.itemAt(items.selected).y) + property var convert: items.selected == 0 ? grid : + items.repeater.mapToItem(background,items.repeater.itemAt(items.selected).x, + items.repeater.itemAt(items.selected).y) - Behavior on x { - NumberAnimation { duration: 200 } - } - Behavior on height { - NumberAnimation { duration: 200 } - } + Behavior on x { NumberAnimation { duration: 200 } } + Behavior on height { NumberAnimation { duration: 200 } } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } -} +} \ No newline at end of file diff --git a/src/activities/crane/crane.js b/src/activities/crane/crane.js old mode 100755 new mode 100644 index 0ee4e890a..114042fbf --- a/src/activities/crane/crane.js +++ b/src/activities/crane/crane.js @@ -1,306 +1,317 @@ /* GCompris - crane.js * * Copyright (C) 2016 Stefan Toncu * * Authors: * (GTK+ version) * Stefan Toncu (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 . */ .pragma library .import QtQuick 2.0 as Quick .import "qrc:/gcompris/src/core/core.js" as Core var currentLevel = 0 var numberOfLevel = 10 var items var url = "qrc:/gcompris/src/activities/crane/resource/" var showGrid = [1,1,1,0,0,1,1,0,0,0] var howManyFigures = [3,3,3,4,5,5,6,7,8,9,10,11,12,13] var allNames = ["bulb.svg","letter-a.svg","letter-b.svg", "rectangle1.svg","rectangle2.svg","square1.svg", "square2.svg","triangle1.svg","triangle2.svg", "tux.svg","water_drop1.svg","water_drop2.svg", "water_spot1.svg","water_spot2.svg"] var words = ["cat","dog","win","good","happy"] var names = [] var names2 = [] +var good = [] function start(items_) { items = items_ currentLevel = 0 initLevel() } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 init() } function init() { items.columns = 7 items.rows = 6 items.gameFinished = false setRandomModel() + for(var i = 0; i < names.length; i++) { + if (items.repeater.itemAt(i).source != "") { + items.repeater.itemAt(i).initialIndex = i + good[i] = i + } + else { + items.repeater.itemAt(i).initialIndex = -1 + good[i] = -1 + } + } + //select the first item in the grid for(var i = 0; i < items.repeater.count; i++) { if (items.repeater.itemAt(i).source != "") { items.selected = i break } } //set opacity for first item's "selection frame" items.repeater.itemAt(items.selected).selected.opacity = 1 //show or hide the grid if (showGrid[currentLevel]) items.showGrid1.opacity = 1 else items.showGrid1.opacity = 0 } function setRandomModel(){ var numbers = [] for (var i = 0; i < items.columns * items.rows; i++){ names[i] = "" // reset the board names2[i] = "" numbers[i] = i; // generate columns*rows numbers } if (currentLevel >= words.length) { // randomize the names Core.shuffle(allNames) //get "howManyFigures[currentLevel]" random numbers Core.shuffle(numbers) for (i = 0; i < howManyFigures[currentLevel]; i++) names[numbers[i]] = url + allNames[i] Core.shuffle(numbers) for (i = 0; i < howManyFigures[currentLevel]; i++) names2[numbers[i]] = url + allNames[i] } else { var model = setModel() for (i = 0; i < model.length; i++) { if (model[i] != "") { names[i] = model[i] names2[i] = model[i] } } Core.shuffle(names) } items.repeater.model = names.length items.modelRepeater.model = names2.length items.gridRepeater.model = names.length for (i = 0; i < names.length; i++) { items.repeater.itemAt(i).source = names[i] items.repeater.itemAt(i).opac = 0 items.modelRepeater.itemAt(i).source = names2[i] } } function setModel() { var model = [] for (var i = 0; i < items.columns * items.rows; i++){ model[i] = "" } var randomRow = Math.floor(Math.random() * items.rows) var randomCol = Math.floor(Math.random() * items.columns) if (items.columns - randomCol - words[currentLevel].length < 0) randomCol = randomCol - Math.abs(items.columns - randomCol - words[currentLevel].length) for (i=0; i items.repeater.itemAt(i).initialIndex) { + min = items.repeater.itemAt(i).initialIndex + indexx = i + } } - } - for (i = 0; i < index-1; i++) { - if (items.repeater.itemAt(i).source != "") { - return i + if (items.repeater.itemAt(i).initialIndex >= 0 && realMin > items.repeater.itemAt(i).initialIndex) { + realMin = items.repeater.itemAt(i).initialIndex + realMinIndex = i } } - return -1; -} - - -function getNextIndex(source) { - var length = names.length - - //find index of curent image in ordonated "names" list - for(var i = 0; i < length; i++) - if (names[i] == source) { - break - } - - //print("indexOf: ", names.indexOf(source)) - - //go to next index - i++ - - //bool variable - var ok = false - - //search from current index - for (; i good[index] && min > good[i]) { +// min = good[i] +// indexx = i +// } +// } +// if (min!=100) { +// print("found after index") +// return indexx +// } + +// for (i = 0; i < good.length; i++) { +// if (good[i] > 0 && min > good[i]) { +// min = good[i] +// indexx = i +// } +// } + +// print("found before index") +// return indexx +//} + //touchscreen gestures function gesture(deltax, deltay) { if (Math.abs(deltax) > 40 || Math.abs(deltay) > 40) { if (deltax > 30 && Math.abs(deltay) < items.sensivity) { move("right") } else if (deltax < -30 && Math.abs(deltay) < items.sensivity) { move("left") } else if (Math.abs(deltax) < items.sensivity && deltay > 30) { move("down") } else if (Math.abs(deltax) < items.sensivity && deltay < 30) { move("up") } } } //depeding on the command, make a move to left/right/up/down or select next item function move(command) { if (items.ok == true && items.gameFinished == false) { var item = items.repeater.itemAt(items.selected) if (command === "left") { - if (items.selected % items.columns != 0) + if (items.selected % items.columns != 0) { +// var aux = good[items.selected-1] +// good[items.selected-1] = good[items.selected] +// good[items.selected] = aux makeMove(item,-item.width,item.x,-1,"x") + } } else if (command === "right") { - if ((items.selected+1) % items.columns != 0) + if ((items.selected+1) % items.columns != 0) { +// aux = good[items.selected+1] +// good[items.selected+1] = good[items.selected] +// good[items.selected] = aux makeMove(item,item.width,item.x,1,"x") + } } else if (command === "up") { - if (items.selected > items.columns-1) + if (items.selected > items.columns-1) { +// aux = good[items.selected-items.columns] +// good[items.selected-items.columns] = good[items.selected] +// good[items.selected] = aux makeMove(item,-item.height,item.y,-items.columns,"y") + } } else if (command === "down") { - if (items.selected < (items.repeater.count-items.columns)) + if (items.selected < (items.repeater.count-items.columns)) { +// aux = good[items.selected+items.columns] +// good[items.selected+items.columns] = good[items.selected] +// good[items.selected] = aux makeMove(item,item.height,item.y,items.columns,"y") + } } else if (command === "next") { items.repeater.itemAt(items.selected).selected.opacity = 0 - items.selected = (currentLevel < words.length) ? getNextIndex1(items.selected) : getNextIndex(items.repeater.itemAt(items.selected).source) +// items.selected = getNextIndex(items.selected) + items.selected = newFunction() items.repeater.itemAt(items.selected).selected.opacity = 1 } } } //set the environment for making a move and start the animation function makeMove(item,distance,startPoint,add,animationProperty) { if (items.repeater.itemAt(items.selected+add).source == "") { //setup the animation item.distance = distance item.indexChange = add item.startPoint = startPoint item.animationProperty = animationProperty //start the animation item.anim.start() //update the selected item items.selected += add; } } //check the answer; advance to next level if the answer is good function checkAnswer() { var count = 0 for (var i = 0; i < items.repeater.count; i++) { if (items.repeater.itemAt(i).source != items.modelRepeater.itemAt(i).source){ count = -1 } } if (count == 0) { items.bonus.good("flower") items.gameFinished = true } } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); -} +} \ No newline at end of file diff --git a/src/activities/crane/resource/readme b/src/activities/crane/resource/README similarity index 100% rename from src/activities/crane/resource/readme rename to src/activities/crane/resource/README diff --git a/src/activities/crane/resource/Letters/a.svg b/src/activities/crane/resource/letters/a.svg similarity index 100% rename from src/activities/crane/resource/Letters/a.svg rename to src/activities/crane/resource/letters/a.svg diff --git a/src/activities/crane/resource/Letters/b.svg b/src/activities/crane/resource/letters/b.svg similarity index 100% rename from src/activities/crane/resource/Letters/b.svg rename to src/activities/crane/resource/letters/b.svg diff --git a/src/activities/crane/resource/Letters/c.svg b/src/activities/crane/resource/letters/c.svg similarity index 100% rename from src/activities/crane/resource/Letters/c.svg rename to src/activities/crane/resource/letters/c.svg diff --git a/src/activities/crane/resource/Letters/d.svg b/src/activities/crane/resource/letters/d.svg similarity index 100% rename from src/activities/crane/resource/Letters/d.svg rename to src/activities/crane/resource/letters/d.svg diff --git a/src/activities/crane/resource/Letters/e.svg b/src/activities/crane/resource/letters/e.svg similarity index 100% rename from src/activities/crane/resource/Letters/e.svg rename to src/activities/crane/resource/letters/e.svg diff --git a/src/activities/crane/resource/Letters/f.svg b/src/activities/crane/resource/letters/f.svg similarity index 100% rename from src/activities/crane/resource/Letters/f.svg rename to src/activities/crane/resource/letters/f.svg diff --git a/src/activities/crane/resource/Letters/g.svg b/src/activities/crane/resource/letters/g.svg similarity index 100% rename from src/activities/crane/resource/Letters/g.svg rename to src/activities/crane/resource/letters/g.svg diff --git a/src/activities/crane/resource/Letters/h.svg b/src/activities/crane/resource/letters/h.svg similarity index 100% rename from src/activities/crane/resource/Letters/h.svg rename to src/activities/crane/resource/letters/h.svg diff --git a/src/activities/crane/resource/Letters/i.svg b/src/activities/crane/resource/letters/i.svg similarity index 100% rename from src/activities/crane/resource/Letters/i.svg rename to src/activities/crane/resource/letters/i.svg diff --git a/src/activities/crane/resource/Letters/j.svg b/src/activities/crane/resource/letters/j.svg similarity index 100% rename from src/activities/crane/resource/Letters/j.svg rename to src/activities/crane/resource/letters/j.svg diff --git a/src/activities/crane/resource/Letters/k.svg b/src/activities/crane/resource/letters/k.svg similarity index 100% rename from src/activities/crane/resource/Letters/k.svg rename to src/activities/crane/resource/letters/k.svg diff --git a/src/activities/crane/resource/Letters/l.svg b/src/activities/crane/resource/letters/l.svg similarity index 100% rename from src/activities/crane/resource/Letters/l.svg rename to src/activities/crane/resource/letters/l.svg diff --git a/src/activities/crane/resource/Letters/m.svg b/src/activities/crane/resource/letters/m.svg similarity index 100% rename from src/activities/crane/resource/Letters/m.svg rename to src/activities/crane/resource/letters/m.svg diff --git a/src/activities/crane/resource/Letters/n.svg b/src/activities/crane/resource/letters/n.svg similarity index 100% rename from src/activities/crane/resource/Letters/n.svg rename to src/activities/crane/resource/letters/n.svg diff --git a/src/activities/crane/resource/Letters/o.svg b/src/activities/crane/resource/letters/o.svg similarity index 100% rename from src/activities/crane/resource/Letters/o.svg rename to src/activities/crane/resource/letters/o.svg diff --git a/src/activities/crane/resource/Letters/p.svg b/src/activities/crane/resource/letters/p.svg similarity index 100% rename from src/activities/crane/resource/Letters/p.svg rename to src/activities/crane/resource/letters/p.svg diff --git a/src/activities/crane/resource/Letters/q.svg b/src/activities/crane/resource/letters/q.svg similarity index 100% rename from src/activities/crane/resource/Letters/q.svg rename to src/activities/crane/resource/letters/q.svg diff --git a/src/activities/crane/resource/Letters/r.svg b/src/activities/crane/resource/letters/r.svg similarity index 100% rename from src/activities/crane/resource/Letters/r.svg rename to src/activities/crane/resource/letters/r.svg diff --git a/src/activities/crane/resource/Letters/s.svg b/src/activities/crane/resource/letters/s.svg similarity index 100% rename from src/activities/crane/resource/Letters/s.svg rename to src/activities/crane/resource/letters/s.svg diff --git a/src/activities/crane/resource/Letters/t.svg b/src/activities/crane/resource/letters/t.svg similarity index 100% rename from src/activities/crane/resource/Letters/t.svg rename to src/activities/crane/resource/letters/t.svg diff --git a/src/activities/crane/resource/Letters/u.svg b/src/activities/crane/resource/letters/u.svg similarity index 100% rename from src/activities/crane/resource/Letters/u.svg rename to src/activities/crane/resource/letters/u.svg diff --git a/src/activities/crane/resource/Letters/v.svg b/src/activities/crane/resource/letters/v.svg similarity index 100% rename from src/activities/crane/resource/Letters/v.svg rename to src/activities/crane/resource/letters/v.svg diff --git a/src/activities/crane/resource/Letters/w.svg b/src/activities/crane/resource/letters/w.svg similarity index 100% rename from src/activities/crane/resource/Letters/w.svg rename to src/activities/crane/resource/letters/w.svg diff --git a/src/activities/crane/resource/Letters/x.svg b/src/activities/crane/resource/letters/x.svg similarity index 100% rename from src/activities/crane/resource/Letters/x.svg rename to src/activities/crane/resource/letters/x.svg diff --git a/src/activities/crane/resource/Letters/y.svg b/src/activities/crane/resource/letters/y.svg similarity index 100% rename from src/activities/crane/resource/Letters/y.svg rename to src/activities/crane/resource/letters/y.svg diff --git a/src/activities/crane/resource/Letters/z.svg b/src/activities/crane/resource/letters/z.svg similarity index 100% rename from src/activities/crane/resource/Letters/z.svg rename to src/activities/crane/resource/letters/z.svg