diff --git a/src/activities/drawing/ColorDialog.qml b/src/activities/drawing/ColorDialog.qml index 5b1a4dd68..ce24c9e6f 100644 --- a/src/activities/drawing/ColorDialog.qml +++ b/src/activities/drawing/ColorDialog.qml @@ -1,199 +1,199 @@ /* GCompris - ColorDialog.qml * * Copyright (C) 2018 Amit Sagtani * * 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 "drawing.js" as Activity import "qrc:/gcompris/src/core/core.js" as Core Rectangle { id: picker width: background.width * 0.20 height: background.height * 0.33 color: "transparent" property real hue property real saturation property real lightness - property int barHeight: height - property int barWidth: width * 0.25 + property real barHeight: height + property real barWidth: width * 0.25 property color currentColorCode: picker.currentColor() function currentColor() { return Qt.hsla(picker.hue, picker.saturation, picker.lightness, 1.0) } function updateColor(color) { // QML does not expose any way of getting the components of a color // parsed by Qt, thus we have to to the parsing ourselves (this breaks // named colors) if (color[0] == '"') { color = color.slice(1, 8); } if (color[0] == '#') { color = color.slice(1); } var r = parseInt(color.slice(0, 2), 16) / 255; var g = parseInt(color.slice(2, 4), 16) / 255; var b = parseInt(color.slice(4, 6), 16) / 255; // Formulae taken from ColorPicker.qml, Plasma Workspace, // Copyright 2013 Marco Martin var min = Math.min(r, Math.min(g, b)) var max = Math.max(r, Math.max(g, b)) var c = max - min var h if (c == 0) { h = 0 } else if (max == r) { h = ((g - b) / c) % 6 } else if (max == g) { h = ((b - r) / c) + 2 } else if (max == b) { h = ((r - g) / c) + 4 } - picker.hue = (1/6) * h + picker.hue = (1 / 6) * h console.log(picker.hue) picker.saturation = (c / (1 - Math.abs(2 * ((max + min) / 2) - 1))) - picker.lightness = (max + min)/2 + picker.lightness = (max + min) / 2 sMarker.y = saturation * barHeight - hsMarker.y = hue * barHeight + hsMarker.y = picker.hue >= 0 ? hue * barHeight : (1 + hue) * barHeight lsMarker.y = (1 - lightness) * barHeight return true; } // Vertical bar that displays the hue of the color MouseArea { id: hueBar width: picker.barWidth height: picker.barHeight anchors.left: parent.left anchors.leftMargin: 10 onPositionChanged: { picker.hue = mouse.y / height hsMarker.y = mouse.y > hueBar.y+hueBar.height ? Math.min(hueBar.y + hueBar.height - 2 , mouse.y) : Math.max(hueBar.y, mouse.y) } // Display the colors Rectangle { anchors.fill: parent gradient: Gradient { GradientStop { position: 0.0/6.0; color: Qt.hsla(0.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 1.0/6.0; color: Qt.hsla(1.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 2.0/6.0; color: Qt.hsla(2.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 3.0/6.0; color: Qt.hsla(3.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 4.0/6.0; color: Qt.hsla(4.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 5.0/6.0; color: Qt.hsla(5.0/6.0, 1, picker.lightness, 1) } GradientStop { position: 6.0/6.0; color: Qt.hsla(6.0/6.0, 1, picker.lightness, 1) } } } // Marker Rectangle { id: hsMarker width: picker.barWidth height: 10 radius: 2 y: hueBar.y + hueBar.height / 2 anchors.horizontalCenter: hueBar.horizontalCenter color: "transparent" border { color: "white" width: 2 } } } //Vertical bar that displays the saturation of the color MouseArea { id: saturationBar width: picker.barWidth height: picker.barHeight anchors.left: hueBar.right anchors.leftMargin: 10 onPositionChanged: { - picker.saturation = mouse.y/height + picker.saturation = mouse.y / height sMarker.y = mouse.y > saturationBar.y+saturationBar.height ? Math.min(saturationBar.y + saturationBar.height - 2 , mouse.y) : Math.max(saturationBar.y, mouse.y) } Rectangle { anchors.fill: parent gradient: Gradient { GradientStop { position: 0.0; color: Qt.hsla(picker.hue, 0, picker.lightness, 0) } GradientStop { position: 1.0; color: Qt.hsla(picker.hue, 1, picker.lightness, 1) } } } Rectangle { id: sMarker width: picker.barWidth height: 10 radius: 2 y: saturationBar.height * (1 - picker.saturation) color: "transparent" border { color: "white" width: 2 } } } // Vertical bar that displays the lightness of the color MouseArea { id: lightnessBar width: picker.barWidth height: picker.barHeight anchors.left: saturationBar.right anchors.leftMargin: 7 onPositionChanged: { picker.lightness = 1 - mouse.y / height lsMarker.y = lightnessBar.height * (1 - picker.lightness) } Rectangle { anchors.fill: parent gradient: Gradient { GradientStop { position: 0.0; color: Qt.hsla(picker.hue, picker.saturation, 1, 1) } GradientStop { position: 0.5; color: Qt.hsla(picker.hue, picker.saturation, 0.5, 1) } GradientStop { position: 1.0; color: Qt.hsla(picker.hue, picker.saturation, 0, 1) } } } Rectangle { id: lsMarker width: picker.barWidth height: 10 radius: 2 y: lightnessBar.height * (1 - picker.lightness) color: "transparent" border { color: "white" width: 2 } } } } diff --git a/src/activities/drawing/FoldablePanels.qml b/src/activities/drawing/FoldablePanels.qml index 528f4f4ff..2748684e7 100644 --- a/src/activities/drawing/FoldablePanels.qml +++ b/src/activities/drawing/FoldablePanels.qml @@ -1,439 +1,447 @@ /* GCompris - FoldablePanels.qml * * Copyright (C) 2018 Amit Sagtani * * 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 QtQuick.Controls 1.5 import QtQuick.Controls.Styles 1.4 import "../../core" import "drawing.js" as Activity import "qrc:/gcompris/src/core/core.js" as Core Item { id: root property int tabWidth: background.width * 0.15 property int tabHeight: background.height * 0.06 property alias colorModel: colorModel property string activePanel: "null" property alias toolsMode: toolsMode property color panelColor: "#1A1A1B" ListModel { id: menuModel ListElement { itemName: qsTr("Save") imgSource: "qrc:/gcompris/src/activities/drawing/resource/filesaveas.svg" } ListElement { itemName: qsTr("Load") imgSource: "qrc:/gcompris/src/activities/drawing/resource/fileopen.svg" } ListElement { itemName: qsTr("Undo") imgSource: "qrc:/gcompris/src/activities/drawing/resource/undo.svg" } ListElement { itemName: qsTr("Redo") imgSource: "qrc:/gcompris/src/activities/drawing/resource/redo.svg" } ListElement { itemName: qsTr("Erase all") imgSource: "qrc:/gcompris/src/activities/drawing/resource/empty.svg" } ListElement { itemName: qsTr("Background color") imgSource: "qrc:/gcompris/src/activities/drawing/resource/color_wheel.svg" } ListElement { itemName: qsTr("Export to PNG") imgSource: "qrc:/gcompris/src/activities/drawing/resource/empty.svg" } } ListModel { id: toolsModel - ListElement { itemName: qsTr("Pencil") - imgSource: "qrc:/gcompris/src/activities/drawing/resource/pen.svg" } +// ListElement { itemName: qsTr("Pencil") +// imgSource: "qrc:/gcompris/src/activities/drawing/resource/pen.svg" } + ListElement { itemName: qsTr("Brush") + imgSource: "qrc:/gcompris/src/activities/drawing/resource/brush_paint.png" } ListElement { itemName: qsTr("Geometric") imgSource: "qrc:/gcompris/src/activities/drawing/resource/empty.svg" } ListElement { itemName: qsTr("Text") imgSource: "qrc:/gcompris/src/activities/drawing/resource/empty.svg" } - ListElement { itemName: qsTr("Brush") - imgSource: "qrc:/gcompris/src/activities/drawing/resource/brush_paint.png" } ListElement { itemName: qsTr("Eraser") imgSource: "qrc:/gcompris/src/activities/drawing/resource/erase.svg" } ListElement { itemName: qsTr("Bucket fill") imgSource: "qrc:/gcompris/src/activities/drawing/resource/fill.svg" } } ListModel { id: colorModel ListElement {colorCode: "#ff0000"} ListElement {colorCode: "#000000"} ListElement {colorCode: "#0000ff"} ListElement {colorCode: "#ffff00"} ListElement {colorCode: "#00ffff"} ListElement {colorCode: "#ff00ff"} ListElement {colorCode: "#800000"} ListElement {colorCode: "#000080"} ListElement {colorCode: "#ff4500"} ListElement {colorCode: "#A0A0A0"} ListElement {colorCode: "#d2691e"} ListElement {colorCode: "#8b008b"} } Rectangle { id: menuTitle width: root.tabWidth height: root.tabHeight radius: 10 color: panelColor border.color: "white" y: -7 MouseArea { anchors.fill: parent enabled: (menuPanel.y < -5 && activePanel != "menuPanel") || (menuPanel.y > -5 && activePanel === "menuPanel") onClicked: { animTarget = menuTitle colorGrid.visible = false menuGrid.visible = true root.activePanel = "menuPanel" if(menuPanel.panelUnFolded) { foldAnimation.start() } else { menuGrid.model = menuModel menuTitle.visible = true menuGrid.visible = true unfoldAnimation.start() } } } GCText { text: qsTr("Menu") fontSize: tinySize anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap fontSizeMode: Text.Fit color: "white" } } Rectangle { id: toolsTitle width: root.tabWidth height: root.tabHeight radius: 10 color: panelColor border.color: "white" x: width + 2 y: -7 MouseArea { anchors.fill: parent enabled: (menuPanel.y < -5 && activePanel != "toolsPanel") || (menuPanel.y > -5 && activePanel === "toolsPanel") onClicked: { animTarget = toolsTitle colorGrid.visible = false menuGrid.visible = true root.activePanel = "toolsPanel" if(menuPanel.panelUnFolded) { foldAnimation.start() } else { toolsTitle.visible = true menuGrid.model = toolsModel menuGrid.visible = true unfoldAnimation.start() } } } GCText { text: qsTr("Tools") fontSize: tinySize anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap fontSizeMode: Text.Fit color: "white" } } Rectangle { id: colorsTitle width: root.tabWidth height: root.tabHeight radius: 10 color: panelColor border.color: "white" x: background.width - 2 * width - 2 y: -7 z: menuPanel.z - 1 MouseArea { anchors.fill: parent enabled: (menuPanel.y < -5 && activePanel != "colorPanel") || (menuPanel.y > -5 && activePanel === "colorPanel") onClicked: { animTarget = colorsTitle menuGrid.visible = false colorGrid.visible = true root.activePanel = "colorPanel" if(menuPanel.panelUnFolded) { foldAnimation.start() } else { colorsTitle.visible = true unfoldAnimation.start() } } } GCText { text: qsTr("Color") fontSize: tinySize anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap fontSizeMode: Text.Fit color: "white" } } Rectangle { id: toolsOptionTitle width: root.tabWidth height: root.tabHeight radius: 10 color: panelColor border.color: "white" x: background.width - width y: -7 MouseArea { anchors.fill: parent enabled: (menuPanel.y < -5 && activePanel != "toolOptions") || (menuPanel.y > -5 && activePanel === "toolOptions") onClicked: { animTarget = toolsOptionTitle root.activePanel = "toolOptions" menuGrid.visible = false colorGrid.visible = false if(menuPanel.panelUnFolded) { foldAnimation.start() } else { toolsOptionTitle.visible = true unfoldAnimation.start() } } } GCText { text: qsTr("Tool Options") fontSize: tinySize anchors.fill: parent + fontSizeMode: Text.Fit horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter - fontSizeMode: Text.Fit + wrapMode: Text.WordWrap color: "white" } } property var animTarget: menuTitle NumberAnimation { id: unfoldTitle target: animTarget property: "y" to: menuPanel.height - 7 duration: 200 easing.type: Easing.InOutQuad } NumberAnimation { id: foldTitle target: animTarget property: "y" to: -7 duration: 200 easing.type: Easing.InOutQuad onStopped: root.activePanel = "null" } Rectangle { id: menuPanel anchors.leftMargin: 5 width: background.width height: background.height / 2.4 color: panelColor y: -height border.color: "white" property bool panelUnFolded: y >= -5 NumberAnimation { id: foldAnimation target: menuPanel property: "y" to: - menuPanel.height duration: 200 easing.type: Easing.InOutQuad onStarted: foldTitle.start() } NumberAnimation { id: unfoldAnimation target: menuPanel property: "y" to: 0 duration: 200 easing.type: Easing.InOutQuad onStarted: unfoldTitle.start() } GridView { id: menuGrid width: parent.width * 0.75 height: parent.height * 0.80 anchors.centerIn: parent visible: root.activePanel == "menuPanel" || root.activePanel == "toolsPanel" anchors.topMargin: 30 cellWidth: width / 4 cellHeight: height / 2.2 model: menuModel delegate:Item { Image { id: img source: imgSource sourceSize.width: menuGrid.cellWidth * 0.60 sourceSize.height: menuGrid.cellHeight * 0.60 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: parent.scale = 1.1 onExited: parent.scale = 1.0 onClicked: { console.log(itemName) Activity.selectTool(itemName) foldAnimation.start() } } } GCText { text: itemName + width: root.tabWidth anchors.horizontalCenter: img.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter anchors.top: img.bottom + wrapMode: Text.WordWrap fontSize: tinySize color: "white" } } } GridView { id: colorGrid width: parent.width * 0.75 height: parent.height * 0.80 anchors.left: selectedColor.right anchors.verticalCenter: menuPanel.verticalCenter anchors.leftMargin: 30 anchors.rightMargin: 10 anchors.topMargin: 10 cellWidth: width / 4.7 cellHeight: height / 3.6 model: colorModel visible: root.activePanel == "colorPanel" z: 1800 delegate: Rectangle { id: root1 radius: 8 width: colorGrid.cellWidth * 0.80 height: colorGrid.cellHeight * 0.90 color: modelData - scale: items.activeColorIndex === index ? 1.2 : 1 + //scale: items.activeColorIndex === index ? 1.2 : 1 border.width: 3 - border.color: modelData + border.color: items.activeColorIndex === index ? "grey" : modelData MouseArea { anchors.fill: parent hoverEnabled: true onEntered: { if(items.activeColorIndex != index) { parent.border.color = "grey" root1.scale = 1.1 } } onExited: { if(items.activeColorIndex != index) { root1.scale = 1 parent.border.color = modelData } } // set this color as current paint color onClicked: { items.activeColorIndex = index items.paintColor = root1.color background.hideExpandedTools() items.paintColor = color background.reloadSelectedPen() colorPicker.updateColor((items.paintColor).toString()) foldAnimation.start() } } } } ColorDialog { id: colorPicker anchors.left: menuPanel.left anchors.verticalCenter: menuPanel.verticalCenter visible: colorGrid.visible anchors.leftMargin: 20 } Rectangle { id: selectedColor width: menuPanel.width * 0.08 height: menuPanel.height * 0.30 visible: colorGrid.visible radius: 8 border.width: 3 z: colorGrid.z anchors.left: colorPicker.right anchors.leftMargin: 10 anchors.bottom: colorGrid.bottom anchors.bottomMargin: 30 color: colorPicker.currentColorCode MouseArea { anchors.fill: parent onClicked: { items.paintColor = selectedColor.color animTarget = colorsTitle foldAnimation.start() } } } Button { style: GCButtonStyle { theme: "light" } text: qsTr("Save") width: selectedColor.width anchors.left: selectedColor.left anchors.bottomMargin: 30 visible: colorGrid.visible anchors.bottom: selectedColor.top onClicked: { root.colorModel.remove(items.activeColorIndex) root.colorModel.insert(items.activeColorIndex, {colorCode: (colorPicker.currentColor()).toString()}) items.paintColor = (colorPicker.currentColor()).toString() } } ToolsMode { id: toolsMode visible: root.activePanel == "toolOptions" } } Rectangle { width: root.tabWidth height: 8 x: animTarget.x y: animTarget.y color: panelColor } } diff --git a/src/activities/drawing/Thickness.qml b/src/activities/drawing/Thickness.qml index d924a8880..16f8dd30e 100644 --- a/src/activities/drawing/Thickness.qml +++ b/src/activities/drawing/Thickness.qml @@ -1,69 +1,73 @@ /* GCompris - Thickness.qml * * Copyright (C) 2016 Toncu Stefan + * 2018 Amit Sagtani * * 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 Rectangle { id: frame + + property bool horizontalScreen: background.width > background.height + color: items.sizeS == Math.floor(lineSize * 15) ? "#ffff66" : "#ffffb3" - width: 40 - height: 40 - radius: 8 + width: horizontalScreen ? 40 : 20 + height: width + radius: horizontalScreen ? 8 : 4 border.color: "#cccc00" border.width: 2 opacity: items.sizeS == Math.floor(lineSize * 15) ? 1 : 0.7 anchors.verticalCenter: parent.verticalCenter property real lineSize: 0.5 Rectangle { id: thickness color: items.paintColor - radius: 30 - width: lineSize * 25 - height: lineSize * 25 + radius: horizontalScreen ? 30 : 10 + width: horizontalScreen ? lineSize * 25 : lineSize * 10 + height: width anchors.centerIn: parent } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true onClicked: { background.hideExpandedTools() items.sizeS = parent.lineSize * 18 print("frame.lineSize " + Math.floor(frame.lineSize * 15)) print("items.sizeS: " + items.sizeS) } states: State { name: "scaled"; when: mouseArea.containsMouse PropertyChanges { target: frame opacity: 1 scale: 1.2 } } transitions: Transition { NumberAnimation { properties: "scale"; easing.type: Easing.OutCubic } } } } diff --git a/src/activities/drawing/ToolsSize.qml b/src/activities/drawing/ToolsSize.qml index 3160eca31..c9c8318bf 100644 --- a/src/activities/drawing/ToolsSize.qml +++ b/src/activities/drawing/ToolsSize.qml @@ -1,53 +1,53 @@ /* GCompris - ToolsSize.qml * * Copyright (C) 2018 Amit Sagtani * * 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 QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.0 import GCompris 1.0 import "../../core" import "drawing.js" as Activity Item { id: toolsSize - width: background.width > background.height ? background.width * 0.30 : background.width * 0.30 + width: background.width * 0.30 height: background.height * 0.35 GCSlider { id: slider + width: parent.width anchors.centerIn: parent - //anchors.verticalCenterOffset: 30 value: items.sizeS minimumValue: 2 maximumValue: 24 onValueChanged: items.sizeS = value stepSize: 2 } Row { id: thicknessRow spacing: slider.width / 4.6 x: slider.x anchors.bottom: slider.top Thickness { lineSize: 0.13 } Thickness { lineSize: 0.66 } Thickness { lineSize: 1.00 } Thickness { lineSize: 1.60 } } } diff --git a/src/activities/drawing/drawing.js b/src/activities/drawing/drawing.js index af22e8210..f15855091 100644 --- a/src/activities/drawing/drawing.js +++ b/src/activities/drawing/drawing.js @@ -1,429 +1,429 @@ /* GCompris - drawing.js * * Copyright (C) 2016 Toncu Stefan * * 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 url = "qrc:/gcompris/src/activities/drawing/resource/" var currentLevel = 0 var numberOfLevel = 4 var items var loadImagesSource = [ "qrc:/gcompris/src/activities/photo_hunter/resource/photo1.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo2.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo3.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo4.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo5.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo6.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo7.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo8.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo9.svg", "qrc:/gcompris/src/activities/photo_hunter/resource/photo10.svg" ] var undo = [] var redo = [] var userFile = "file://" + GCompris.ApplicationInfo.getSharedWritablePath() + "/paint/" + "levels-user.json" var dataset = null var ctx var points = [] var connectedPoints = [] function start(items_) { items = items_ currentLevel = 0 items.toolSelected = "pencil" items.paintColor = "#000000" initLevel() } function stop() { } function initLevel() { dataset = null points = [] connectedPoints = [] undo = [] redo = [] ctx = items.canvas.getContext("2d") ctx.fillStyle = "#ffffff" ctx.beginPath() ctx.clearRect(0, 0, items.background.width, items.background.height) ctx.moveTo(0, 0) ctx.lineTo(items.background.width, 0) ctx.lineTo(items.background.width, items.background.height) ctx.lineTo(0, items.background.height) ctx.closePath() ctx.fill() items.canvas.requestPaint() items.next = false items.next2 = false undo = ["data:image/pngbase64,iVBORw0KGgoAAAANSUhEUgAAA4sAAAOLCAYAAAD5ExZjAAAACXBIWXMAAA7EAAAOxAGVKw4bAAATLElEQVR4nO3XsQ0AIRDAsOf33/lokTIAFPYEabNmZj4AAAA4/LcDAAAAeI9ZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgzCIAAABhFgEAAAizCAAAQJhFAAAAwiwCAAAQZhEAAIAwiwAAAIRZBAAAIMwiAAAAYRYBAAAIswgAAECYRQAAAMIsAgAAEGYRAACAMIsAAACEWQQAACDMIgAAAGEWAQAACLMIAABAmEUAAADCLAIAABBmEQAAgDCLAAAAhFkEAAAgNq0MCxI5gV9wAAAAAElFTkSuQmCC"] // if the width/height is changed, the drawing is reset and repainted the last image saved if (items.widthHeightChanged) { // load the image items.canvas.url = items.lastUrl items.canvas.loadImage(items.lastUrl) // reset the flag to false items.widthHeightChanged = false } //load saved paintings from file parseImageSaved() items.gridView2.model = dataset getPattern() items.background.started = true items.background.hideExpandedTools() } function getPattern() { var dotWidth = 20, dotDistance = 5 var patternCtx = items.shape.getContext("2d") patternCtx.clearRect(0, 0, items.shape.width, items.shape.height) items.shape.width = items.shape.height = dotWidth + dotDistance patternCtx.fillStyle = items.paintColor patternCtx.beginPath() patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false); patternCtx.closePath() patternCtx.fill() items.shape.requestPaint() } function getPattern2() { var lineSize = 10, lineWidth = 5 var patternCtx = items.shape.getContext("2d") patternCtx.clearRect(0, 0, items.shape.width, items.shape.height) items.shape.width = items.shape.height = lineSize patternCtx.strokeStyle = items.paintColor patternCtx.lineWidth = lineWidth patternCtx.beginPath() patternCtx.moveTo(0, lineWidth) patternCtx.lineTo(lineSize, lineWidth) patternCtx.closePath() patternCtx.stroke() } function getPattern3() { var lineSize = 20, lineWidth = 10 var ctx = items.shape.getContext("2d") ctx.clearRect(0, 0, items.shape.width, items.shape.height) items.shape.width = lineWidth; items.shape.height = lineSize; ctx.fillStyle = items.paintColor ctx.fillRect(lineWidth / 2, 0, lineWidth, lineSize); } function getSprayPattern() { var patternCtx = items.shape.getContext("2d") patternCtx.clearRect(0, 0, items.shape.width, items.shape.height) items.shape.width = items.shape.height = 3 patternCtx.fillStyle = items.paintColor patternCtx.fillRect(0, 0, 2, 2); } function getCirclePattern() { var dotWidth = 10, dotDistance = 2.5 var patternCtx = items.shape.getContext("2d") patternCtx.clearRect(0, 0, items.shape.width, items.shape.height) items.shape.width = dotWidth * 0.6 + dotDistance * 2 items.shape.height = items.shape.width patternCtx.strokeStyle = items.paintColor patternCtx.lineWidth = 1 patternCtx.beginPath() patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false); patternCtx.closePath() patternCtx.stroke() } // parse the content of the paintings saved by the user function parseImageSaved() { dataset = items.parser.parseFromUrl(userFile) if (dataset == null) { console.error("ERROR! dataset = []") dataset = [] return } } // if showMessage === true, then show the message Core.showMessageDialog(...), else don't show it function saveToFile(showMessage) { // verify if the path is good var path = userFile.substring(0, userFile.lastIndexOf("/")) if (!items.file.exists(path)) { if (!items.file.mkpath(path)) console.error("Could not create directory " + path) else console.debug("Created directory " + path) } // add current painting to the dataset if (showMessage) dataset = dataset.concat({"imageNumber": 1, "url": items.canvas.toDataURL()}) // save the dataset to json file if (!items.file.write(JSON.stringify(dataset), userFile)) { if (showMessage) Core.showMessageDialog(items.main, //~ singular Error saving %n level to your levels file (%1) //~ plural Error saving %n levels to your levels file (%1) qsTr("Error saving %n level(s) to your levels file (%1)", "", numberOfLevel) .arg(userFile), "", null, "", null, null) } else { if (showMessage) Core.showMessageDialog(items.main, //~ singular Saved %n level to your levels file (%1) //~ plural Saved %n levels to your levels file (%1) qsTr("Saved %n level(s) to your levels file (%1)", "", numberOfLevel) .arg(userFile), "", null, "", null, null) } items.initSave = false //reload the dataset: parseImageSaved() items.gridView2.model = dataset // reset nothingChanged items.nothingChanged = true } // Exports the current drawing in png format. function exportToPng() { var path = GCompris.ApplicationInfo.getSharedWritablePath() + "/drawing" if(!items.file.exists(path)) { if(!items.file.mkpath(path)) { Core.showMessageDialog(items.main, qsTr("Error: could not create the directory %1").arg(path), "", null, "", null, null) console.error("Could not create directory " + path) return; } else console.debug("Created directory " + path) } var i = 0; while(items.file.exists(path + "/drawing" + i.toString() + ".png")) { i += 1 } items.canvas.grabToImage(function(result) { if(result.saveToFile(path + "/drawing" + i.toString() + ".png")) { console.log("File drawing" + i + ".png saved successfully.") Core.showMessageDialog(items.main, qsTr("Saved drawing to %1").arg(path + "/drawing" + i.toString() + ".png"), "", null, "", null, null) } else { Core.showMessageDialog(items.main, qsTr("Error in saving the drawing."), "", null, "", null, null) } }) } function nextLevel() { if(numberOfLevel <= ++currentLevel) { currentLevel = 0 } initLevel() } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel() } function selectTool(toolName) { console.log("Clicked on " + toolName) if(toolName === "Eraser") { items.toolSelected = "eraser" items.background.hideExpandedTools() items.background.reloadSelectedPen() } else if(toolName === "Bucket fill") { items.toolSelected = "fill" items.background.hideExpandedTools() // make the hover over the canvas false items.area.hoverEnabled = false // change the selectBrush tool items.timer.index = 0 items.timer.start() items.background.reloadSelectedPen() } else if(toolName === "Text") { items.toolSelected = "text" items.background.hideExpandedTools() items.background.reloadSelectedPen() // enable the text to follow the cursor movement items.area.hoverEnabled = true // make visible the inputTextFrame items.inputTextFrame.opacity = 1 items.inputTextFrame.z = 1000 // restore input text to "" items.inputText.text = "" } else if(toolName === "Undo") { items.background.hideExpandedTools() if (undo.length > 0 && items.next || undo.length > 1 && items.next == false) { items.undoRedo = true if (items.next) { redo = redo.concat(undo.pop()) } items.next = false items.next2 = true // pop the last image saved from "undo" array items.urlImage = undo.pop() // load the image in the canvas items.canvas.loadImage(items.urlImage) // save the image into the "redo" array redo = redo.concat(items.urlImage) // print("undo: " + undo.length + " redo: " + redo.length + " undo Pressed") } } else if(toolName === "Redo") { items.background.hideExpandedTools() if (redo.length > 0) { items.undoRedo = true if (items.next2) { undo = undo.concat(redo.pop()) } items.next = true items.next2 = false items.urlImage = redo.pop() items.canvas.loadImage(items.urlImage) undo = undo.concat(items.urlImage) // print("undo: " + undo.length + " redo: " + redo.length + " redo Pressed") } } else if(toolName === "Load") { if (items.load.opacity == 0) items.load.opacity = 1 items.background.hideExpandedTools() // mark the pencil as the default tool items.toolSelected = "pencil" // move the main screen to right items.mainRegion.x = items.background.width } else if(toolName === "Save") { saveToFile(true) } else if(toolName === "More Colors") { items.colorPalette.visible = true } else if(toolName === "Modes") { items.toolsMode.visible = true } else if(toolName === "Size") { items.toolsSize.visible = true } else if(toolName === "Erase all") { if (!items.nothingChanged) { items.saveToFilePrompt.buttonPressed = "reload" items.saveToFilePrompt.text = qsTr("Do you want to save your painting before reseting the board?") items.saveToFilePrompt.opacity = 1 items.saveToFilePrompt.z = 200 } else { initLevel() } } else if(toolName === "Geometric") { items.toolSelected = "rectangle" items.lastToolSelected = "rectangle" items.background.hideExpandedTools() items.background.reloadSelectedPen() items.toolsMode.modesModel = items.toolsMode.geometricModes } - else if(toolName === "Pencil") { + else if(toolName === "Brush") { items.toolSelected = "pencil" items.lastToolSelected = "pencil" items.background.hideExpandedTools() items.background.reloadSelectedPen() items.toolsMode.modesModel = items.toolsMode.pencilModes } else if(toolName === "Export to PNG") { exportToPng() } } function selectMode(modeName) { if(modeName === "dot") { items.toolSelected = "pattern" items.patternType = "dot" items.lastToolSelected = "pattern" getPattern() items.background.reloadSelectedPen() } else if(modeName === "pattern2") { items.toolSelected = "pattern" items.patternType = "horizLine" items.lastToolSelected = "pattern" getPattern2() items.background.reloadSelectedPen() } else if(modeName === "pattern3") { items.toolSelected = "pattern" items.patternType = "vertLine" items.lastToolSelected = "pattern" getPattern3() items.background.reloadSelectedPen() } }