diff --git a/src/activities/mosaic/Mosaic.qml b/src/activities/mosaic/Mosaic.qml index 69128b4c4..ba9568fc1 100644 --- a/src/activities/mosaic/Mosaic.qml +++ b/src/activities/mosaic/Mosaic.qml @@ -1,504 +1,502 @@ /* GCompris - mosaic.qml * * Copyright (C) 2014 Bruno Coudoin * * Authors: * Clement coudoin (GTK+ version) * Bruno.coudoin (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 "mosaic.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Image { id: background source: Activity.url + "background.svg" sourceSize.width: Math.max(parent.width, parent.height) fillMode: Image.PreserveAspectCrop anchors.fill: parent signal start signal stop property bool keyboardMode: false property var areaWithKeyboardFocus: selector Component.onCompleted: { dialogActivityConfig.initialize() 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 GCSfx audioEffects: activity.audioEffects property alias question: question property alias answer: answer property alias selector: selector property alias background: background property alias bar: bar property alias bonus: bonus property string selectedItem property var levels: activity.datasetLoader.data property int nbItems - property int selectorLayoutColumns - property int selectorLayoutRows property int questionLayoutColumns property int questionLayoutRows property string modelDisplayLayout } onStart: { Activity.start(items) } onStop: { Activity.stop() } Keys.onLeftPressed: { keyboardMode = true areaWithKeyboardFocus.moveCurrentIndexLeft() } Keys.onRightPressed: { keyboardMode = true areaWithKeyboardFocus.moveCurrentIndexRight() } Keys.onUpPressed: { keyboardMode = true areaWithKeyboardFocus.moveCurrentIndexUp() } Keys.onDownPressed: { keyboardMode = true areaWithKeyboardFocus.moveCurrentIndexDown() } Keys.onEnterPressed: { selectCell() } Keys.onSpacePressed: { selectCell() } Keys.onReturnPressed: { selectCell() } Keys.onTabPressed: { keyboardMode = true areaWithKeyboardFocus.changeAreaWithKeyboardFocus() } function selectCell() { keyboardMode = true areaWithKeyboardFocus.selectCurrentCell(areaWithKeyboardFocus.currentItem) } function fitItems(x_, y_, n_) { var sx var sy var px = Math.ceil(Math.sqrt(n_ * x_ / y_)); if (Math.floor(px * y_ / x_) * px < n_) { sx = y / Math.ceil(px * y_ / x_); } else { sx = x_ / px; } var py = Math.ceil(Math.sqrt(n_ * y_ / x_)); if (Math.floor(py * x_ / y_) * py < n_) { sy = x_ / Math.ceil(x_ * py / y_); } else { sy = y_ / py; } return Math.max(sx, sy); } Rectangle { id: mainArea anchors.top: background.top anchors.bottom: bar.top anchors.left: background.left anchors.right: background.right color: "#00FFFFFF" property int nbItems: 24 property bool horizontal: background.width >= background.height property bool smallQuestionMode: items.modelDisplayLayout === "smaller" property int nbColumns: items.questionLayoutColumns property int nbLines: items.questionLayoutRows property int layoutMargin: 10 states: [ State { name: "horizontal" when: mainArea.horizontal AnchorChanges { target: questionRectangle anchors.top: parent.top anchors.left: parent.left anchors.horizontalCenter: undefined } PropertyChanges { target: answerRectangle height: mainArea.height * 0.66 - mainArea.layoutMargin * 2 width: mainArea.width * 0.5 - mainArea.layoutMargin * 1.5 } AnchorChanges { target: answerRectangle anchors.top: parent.top anchors.left: questionRectangle.right } }, State { name: "vertical" when: !mainArea.horizontal AnchorChanges { target: questionRectangle anchors.top: parent.top anchors.left: parent.left anchors.horizontalCenter: undefined } PropertyChanges { target: answerRectangle height: mainArea.height / 3 - mainArea.layoutMargin * 2 width: mainArea.width - mainArea.layoutMargin * 2 } AnchorChanges { target: answerRectangle anchors.top: questionRectangle.bottom anchors.left: parent.left } } ] // === The Question Area === Rectangle { id: questionRectangle color: "#00FFFFFF" height: answerRectangle.height width: answerRectangle.width anchors.top: mainArea.top anchors.left: mainArea.left anchors.topMargin: mainArea.layoutMargin anchors.leftMargin: mainArea.layoutMargin Rectangle { id: questionRectangleContent anchors.centerIn: parent color: "#55333333" border.color: "black" border.width: 2 radius: 5 states: [ State { name: "smallQuestion" when: mainArea.smallQuestionMode PropertyChanges { target: questionRectangleContent height: answerRectangle.height * 0.7 width: answerRectangle.width * 0.7 } }, State { name: "normalQuestion" when: !mainArea.smallQuestionMode PropertyChanges { target: questionRectangleContent height: answerRectangle.height width: answerRectangle.width } } ] GridView { id: question width: cellWidth * mainArea.nbColumns height: cellHeight * mainArea.nbLines anchors.centerIn: parent anchors.verticalCenterOffset: 2.5 * ApplicationInfo.ratio anchors.horizontalCenterOffset: anchors.verticalCenterOffset cellHeight: cellWidth cellWidth: Math.min(parent.width / mainArea.nbColumns, parent.height / mainArea.nbLines) interactive: false keyNavigationWraps: true delegate: Image { id: imageQuestionId source: Activity.url + modelData fillMode: Image.PreserveAspectFit width: question.cellWidth - 5 * ApplicationInfo.ratio height: width sourceSize.width: width sourceSize.height: height } } } } // === The Answer Area === Rectangle { id: answerRectangle height: mainArea.height * 0.33 - mainArea.layoutMargin * 2 width: mainArea.width - mainArea.layoutMargin * 2 anchors.top: questionRectangle.bottom anchors.left: mainArea.left anchors.topMargin: mainArea.layoutMargin anchors.leftMargin: mainArea.layoutMargin color: "#55333333" border.color: "black" border.width: 2 radius: 5 GridView { id: answer width: cellWidth * mainArea.nbColumns height: cellHeight * mainArea.nbLines anchors.centerIn: parent cellHeight: cellWidth cellWidth: Math.min(parent.width / mainArea.nbColumns, parent.height / mainArea.nbLines) interactive: false keyNavigationWraps: true highlightFollowsCurrentItem: true highlight: Rectangle { color: "red" border.width: 3 border.color: "black" opacity: 0.6 visible: background.keyboardMode && (background.areaWithKeyboardFocus === answer) Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } } Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } } // If the image was directly used as a delegate (without containing it in the item), the highlight element would have been be hard to notice as it would get completely hidden by the image due to the same sizes. delegate: Item { id: cellItem width: answer.cellWidth height: answer.cellHeight readonly property int cellIndex: index Image { id: imageAnswerId source: Activity.url + modelData fillMode: Image.PreserveAspectFit width: answer.cellWidth - 5 * ApplicationInfo.ratio height: width sourceSize.width: width sourceSize.height: height anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: answer.selectCurrentCell(cellItem) } } } function selectCurrentCell(selectedCell) { Activity.answerSelected(selectedCell.cellIndex) } function changeAreaWithKeyboardFocus() { areaWithKeyboardFocus = selector } } } // === The Selector === Rectangle { id: selectorRectangle height: mainArea.height * 0.33 - mainArea.layoutMargin * 2 width: mainArea.width - mainArea.layoutMargin * 2 anchors.top: answerRectangle.bottom anchors.left: mainArea.left anchors.topMargin: mainArea.layoutMargin anchors.leftMargin: mainArea.layoutMargin color: "#661111AA" border.color: "black" border.width: 2 radius: 5 property int selectorItemSize: fitItems(selectorRectangle.width, selectorRectangle.height, selector.count) GridView { id: selector width: parent.width height: parent.height anchors.centerIn: parent anchors.verticalCenterOffset: 2.5 * ApplicationInfo.ratio anchors.horizontalCenterOffset: anchors.verticalCenterOffset cellHeight: selectorRectangle.selectorItemSize cellWidth: selectorRectangle.selectorItemSize interactive: false keyNavigationWraps: true highlightFollowsCurrentItem: true highlight: Rectangle { color: "red" border.width: 3 border.color: "black" opacity: 0.6 visible: background.keyboardMode && (background.areaWithKeyboardFocus === selector) Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } } Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } } delegate: Image { id: imageId source: Activity.url + modelData fillMode: Image.PreserveAspectFit width: selector.cellWidth - 5 * ApplicationInfo.ratio height: width sourceSize.width: width sourceSize.height: height z: iAmSelected ? 10 : 1 readonly property bool iAmSelected: items.selectedItem === modelData readonly property string imageName: modelData states: [ State { name: "notclicked" when: !imageId.iAmSelected && !mouseArea.containsMouse PropertyChanges { target: imageId scale: 0.8 } }, State { name: "clicked" when: mouseArea.pressed PropertyChanges { target: imageId scale: 0.7 } }, State { name: "hover" when: mouseArea.containsMouse PropertyChanges { target: imageId scale: 1 } }, State { name: "selected" when: imageId.iAmSelected PropertyChanges { target: imageId scale: 1 } } ] SequentialAnimation { id: anim running: imageId.iAmSelected loops: Animation.Infinite alwaysRunToEnd: true NumberAnimation { target: imageId property: "rotation" from: 0; to: 10 duration: 200 easing.type: Easing.OutQuad } NumberAnimation { target: imageId property: "rotation" from: 10; to: -10 duration: 400 easing.type: Easing.InOutQuad } NumberAnimation { target: imageId property: "rotation" from: -10; to: 0 duration: 200 easing.type: Easing.InQuad } } Behavior on scale { NumberAnimation { duration: 70 } } MouseArea { id: mouseArea anchors.fill: imageId hoverEnabled: true onClicked: selector.selectCurrentCell(parent) } } function selectCurrentCell(selectedCell) { items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/scroll.wav") items.selectedItem = selectedCell.imageName } function changeAreaWithKeyboardFocus() { areaWithKeyboardFocus = answer } } } } DialogChooseLevel { id: dialogActivityConfig currentActivity: activity.activityInfo onSaveData: { levelFolder = dialogActivityConfig.chosenLevels currentActivity.currentLevels = dialogActivityConfig.chosenLevels ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels) // restart activity on saving background.start() } onClose: { home() } onStartActivity: { background.start() } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level | activityConfig} onHelpClicked: { displayDialog(dialogHelp) } onActivityConfigClicked: { displayDialog(dialogActivityConfig) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/mosaic/mosaic.js b/src/activities/mosaic/mosaic.js index d6c47fae2..314da5b94 100644 --- a/src/activities/mosaic/mosaic.js +++ b/src/activities/mosaic/mosaic.js @@ -1,94 +1,92 @@ /* GCompris - mosaic.js * * Copyright (C) 2014 Bruno Coudoin * * Authors: * Clement coudoin (GTK+ version) * Bruno.coudoin (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.6 as Quick .import "qrc:/gcompris/src/core/core.js" as Core var questionModel var answerModel var selectorModel var url = "qrc:/gcompris/src/activities/mosaic/resource/" var currentLevel = 0 var numberOfLevel var items function start(items_) { items = items_ currentLevel = 0 initLevel() numberOfLevel = items.levels.length } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 items.background.areaWithKeyboardFocus = items.selector items.selectedItem = "" items.nbItems = items.levels[currentLevel].nbOfCells items.questionLayoutColumns = items.levels[currentLevel].layout[0][0] items.questionLayoutRows = items.levels[currentLevel].layout[0][1] - items.selectorLayoutColumns = items.levels[currentLevel].layout[1][0] - items.selectorLayoutRows = items.levels[currentLevel].layout[1][1] items.modelDisplayLayout = items.levels[currentLevel].modelDisplayLayout selectorModel = items.levels[currentLevel].images items.selector.model = selectorModel questionModel = Core.shuffle(selectorModel) items.question.model = questionModel answerModel = new Array() for(var i=0; i < questionModel.length; i++) answerModel.push("die_0.svg") items.answer.model = answerModel } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } function answerSelected(index) { if(!items.selectedItem) return items.audioEffects.play("qrc:/gcompris/src/activities/redraw/resource/brush.wav") answerModel[index] = items.selectedItem items.answer.model = answerModel if(answerModel.toString() === questionModel.toString()) { items.bonus.good("flower") } } diff --git a/src/activities/mosaic/resource/1/Data.qml b/src/activities/mosaic/resource/1/Data.qml index 5741d6b84..3bbf4b4f5 100644 --- a/src/activities/mosaic/resource/1/Data.qml +++ b/src/activities/mosaic/resource/1/Data.qml @@ -1,93 +1,80 @@ /* GCompris - Data.qml * * Copyright (C) 2020 Deepak Kumar * * Authors: * Deepak Kumar * * 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 GCompris 1.0 Data { - objective: qsTr("Up to 6 items are placed on single line.") + objective: qsTr("Up to 5 items are placed on single line.") difficulty: 2 property var images: [ "aquarela_colors.svg", "giraffe.svg", "pencil.svg", "mouse_on_cheese.svg", "mushroom_house.svg", "pencils_paper.svg", "pencils.svg", "white_cake.svg", "die_1.svg", "die_2.svg", "die_3.svg", "die_4.svg", "die_5.svg", "die_6.svg", "die_7.svg", "die_0.svg", "digital_die0.svg", "digital_die1.svg", "digital_die2.svg", "digital_die3.svg", "digital_die4.svg", "digital_die5.svg", "digital_die6.svg", "digital_die7.svg" ] data: [ { "nbOfCells": 3, "layout": [ - [3,1], [3,1] ], "modelDisplayLayout": "smaller", "images": images.slice(0,3) }, { "nbOfCells": 4, "layout": [ - [4,1], [4,1] ], "modelDisplayLayout": "smaller", "images": images.slice(1,5) }, { "nbOfCells": 5, "layout": [ - [5,1], [5,1] ], "modelDisplayLayout": "smaller", "images": images.slice(2,7) - }, - { - "nbOfCells": 6, - "layout": [ - [6,1], - [6,1] - ], - "modelDisplayLayout": "smaller", - "images": images.slice(3,9) - } ] } diff --git a/src/activities/mosaic/resource/2/Data.qml b/src/activities/mosaic/resource/2/Data.qml index 190db2c76..93e57319d 100644 --- a/src/activities/mosaic/resource/2/Data.qml +++ b/src/activities/mosaic/resource/2/Data.qml @@ -1,101 +1,80 @@ /* GCompris - Data.qml * * Copyright (C) 2020 Deepak Kumar * * Authors: * Deepak Kumar * * 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 GCompris 1.0 Data { objective: qsTr("Up to 8 items are placed on single line.") difficulty: 2 property var images: [ "aquarela_colors.svg", "giraffe.svg", "pencil.svg", "mouse_on_cheese.svg", "mushroom_house.svg", "pencils_paper.svg", "pencils.svg", "white_cake.svg", "die_1.svg", "die_2.svg", "die_3.svg", "die_4.svg", "die_5.svg", "die_6.svg", "die_7.svg", "die_0.svg", "digital_die0.svg", "digital_die1.svg", "digital_die2.svg", "digital_die3.svg", "digital_die4.svg", "digital_die5.svg", "digital_die6.svg", "digital_die7.svg" ] data: [ { - "nbOfCells": 3, - "layout": [ - [3,1], - [3,1] - ], - "modelDisplayLayout": "smaller", - "images": images.slice(0,3) - }, - { - "nbOfCells": 4, - "layout": [ - [4,1], - [4,1] - ], - "modelDisplayLayout": "smaller", - "images": images.slice(1,5) - }, - { - "nbOfCells": 5, + "nbOfCells": 6, "layout": [ - [5,1], - [5,1] + [6,1] ], "modelDisplayLayout": "smaller", - "images": images.slice(2,7) + "images": images.slice(3,9) }, { - "nbOfCells": 6, + "nbOfCells": 7, "layout": [ - [6,1], - [6,1] + [7,1] ], "modelDisplayLayout": "smaller", - "images": images.slice(3,9) + "images": images.slice(2,9) }, { "nbOfCells": 8, "layout": [ - [8,1], [8,1] ], "modelDisplayLayout": "smaller", "images": images.slice(5,13) } ] } diff --git a/src/activities/mosaic/resource/3/Data.qml b/src/activities/mosaic/resource/3/Data.qml index 4494a90f6..c0f15f989 100644 --- a/src/activities/mosaic/resource/3/Data.qml +++ b/src/activities/mosaic/resource/3/Data.qml @@ -1,128 +1,120 @@ /* GCompris - Data.qml * * Copyright (C) 2020 Deepak Kumar * * Authors: * Deepak Kumar * * 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 GCompris 1.0 Data { objective: qsTr("Up to 16 items are placed on multiple lines.") difficulty: 3 property var images: [ "aquarela_colors.svg", "giraffe.svg", "pencil.svg", "mouse_on_cheese.svg", "mushroom_house.svg", "pencils_paper.svg", "pencils.svg", "white_cake.svg", "die_1.svg", "die_2.svg", "die_3.svg", "die_4.svg", "die_5.svg", "die_6.svg", "die_7.svg", "die_0.svg", "digital_die0.svg", "digital_die1.svg", "digital_die2.svg", "digital_die3.svg", "digital_die4.svg", "digital_die5.svg", "digital_die6.svg", "digital_die7.svg" ] data: [ { "nbOfCells": 8, "layout": [ - [4,2], - [8,1] + [4,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,8) }, { "nbOfCells": 8, "layout": [ - [4,2], - [8,1] + [4,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(1,9) }, { "nbOfCells": 8, "layout": [ - [4,2], - [8,1] + [4,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(2,10) }, { "nbOfCells": 8, "layout": [ - [4,2], - [8,1] + [4,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(3,11) }, { "nbOfCells": 16, "layout": [ - [4,4], [8,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(4,20) }, { "nbOfCells": 16, "layout": [ - [4,4], [8,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(5,21) }, { "nbOfCells": 16, "layout": [ - [4,4], [8,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(6,22) }, { "nbOfCells": 16, "layout": [ - [4,4], [8,2] ], "modelDisplayLayout": "sameSize", "images": images.slice(2,18) } ] } diff --git a/src/activities/mosaic/resource/4/Data.qml b/src/activities/mosaic/resource/4/Data.qml index 56b1cae28..ab46ffd80 100644 --- a/src/activities/mosaic/resource/4/Data.qml +++ b/src/activities/mosaic/resource/4/Data.qml @@ -1,128 +1,120 @@ /* GCompris - Data.qml * * Copyright (C) 2020 Deepak Kumar * * Authors: * Deepak Kumar * * 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 GCompris 1.0 Data { objective: qsTr("Up to 24 items are placed on multiple lines.") difficulty: 4 property var images: [ "aquarela_colors.svg", "giraffe.svg", "pencil.svg", "mouse_on_cheese.svg", "mushroom_house.svg", "pencils_paper.svg", "pencils.svg", "white_cake.svg", "die_1.svg", "die_2.svg", "die_3.svg", "die_4.svg", "die_5.svg", "die_6.svg", "die_7.svg", "die_0.svg", "digital_die0.svg", "digital_die1.svg", "digital_die2.svg", "digital_die3.svg", "digital_die4.svg", "digital_die5.svg", "digital_die6.svg", "digital_die7.svg" ] data: [ { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) }, { "nbOfCells": 24, "layout": [ - [6,4], - [12,2] + [8,3] ], "modelDisplayLayout": "sameSize", "images": images.slice(0,24) } ] }