diff --git a/src/painteditor/Paint.js b/src/painteditor/Paint.js index 5ca21a0..36dc266 100644 --- a/src/painteditor/Paint.js +++ b/src/painteditor/Paint.js @@ -1,3 +1,10 @@ +// Originally several files (Paint.js, PaintIO.js, PaintLayout.js) +// were all contributing utility functions to the Paint object. +// To consolidate it into a single module, I've combined these below. +// A nice refactor would be to split them back into the "modules," but that will likely involve +// some serious code changes - determining where the relevant Paint.X are called, if any shared +// data needs to be moved, etc. -TM + var Paint = function () {}; Paint.xmlns = 'http://www.w3.org/2000/svg'; @@ -454,3 +461,962 @@ Paint.dragBackground = function (evt) { Paint.cmdForGesture = [Paint.ignore, Paint.mouseDown, Paint.pinchStart, Paint.Scroll]; + +// Originally PaintLayout.js + +///////////////////////////////// +//Layout Setup +///////////////////////////////// + +Paint.layout = function () { + Paint.topbar(); + var div = newHTML('div', 'innerpaint', Paint.frame); + Paint.leftPalette(div); + var workspaceContainer = newHTML('div', 'workspacebkg-container', div); + var workspace = newHTML('div', 'workspacebkg', workspaceContainer); + workspace.setAttribute('id', 'workspacebkg'); + Paint.rightPalette(div); + Paint.colorPalette(Paint.frame); + Paint.selectButton('path'); + Paint.createSVGeditor(workspace); +}; + +///////////////////////////////// +//top bar +///////////////////////////////// + +Paint.topbar = function () { + var pt = newHTML('div', 'paintop', Paint.frame); + Paint.checkMark(pt); + PaintUndo.setup(pt); // plug here the undo + Paint.nameOfcostume(pt); +}; + +Paint.checkMark = function (pt) { + var clicky = newHTML('div', 'paintdone', pt); + clicky.id = 'donecheck'; + if (isTablet) { + clicky.ontouchstart = Paint.backToProject; + } else { + clicky.onmousedown = Paint.backToProject; + } +}; + +Paint.nameOfcostume = function (p) { + var sform = newHTML('form', 'spriteform', p); + sform.name = 'spriteform'; + var ti = newHTML('input', undefined, sform); + ti.onkeypress = undefined; + ti.autocomplete = 'off'; + ti.autocorrect = false; + ti.name = 'name'; + ti.maxLength = 25; + ti.firstTime = true; + ti.onfocus = Paint.nameFocus; + ti.onblur = Paint.nameBlur; + ti.onkeypress = Paint.handleNamePress; + ti.onkeyup = Paint.handleKeyRelease; + sform.onsubmit = Paint.submitNameChange; +}; + +Paint.submitNameChange = function (e) { + e.preventDefault(); + var input = e.target; + input.blur(); +}; + +Paint.nameFocus = function (e) { + e.preventDefault(); + e.stopPropagation(); + var ti = e.target; + ti.firstTime = true; + ScratchJr.activeFocus = ti; + if (isAndroid) { + AndroidInterface.scratchjr_setsoftkeyboardscrolllocation( + ti.getBoundingClientRect().top * window.devicePixelRatio, + ti.getBoundingClientRect().bottom * window.devicePixelRatio + ); + } + Undo.aux = Project.getProject(ScratchJr.stage.currentPage.id); + setTimeout(function () { + ti.setSelectionRange(ti.value.length, ti.value.length); + }, 1); +}; + +Paint.nameBlur = function (e) { + ScratchJr.activeFocus = undefined; + var spr = ScratchJr.getSprite(); + var ti = e.target; + var val = ScratchJr.validate(ti.value, spr.name); + ti.value = val.substring(0, ti.maxLength); + ScratchJr.storyStart('Paint.nameBlur'); +}; + +Paint.handleNamePress = function (e) { + var key = e.keyCode || e.which; + if (key == 13) { + Paint.submitNameChange(e); + } else { + var ti = e.target; + if (ti.firstTime) { + ti.firstTime = false; + ti.value = ''; + } + if (ti.value.length == 25) { + ScratchAudio.sndFX('boing.wav'); + } + } +}; + +Paint.handleKeyRelease = function (e) { + var key = e.keyCode || e.which; + var ti = e.target; + if (key != 8) { + return; + } + if (ti.firstTime) { + ti.firstTime = false; + ti.value = ''; + } +}; + +///////////////////////////////// +//Left Palette +///////////////////////////////// + +Paint.leftPalette = function (div) { + var leftpal = newHTML('div', 'side up', div); + var pal = newHTML('div', 'paintpalette', leftpal); + pal.setAttribute('id', 'paintpalette'); + Paint.setupEditPalette(pal); + Paint.createSizeSelector(pal); +}; + +Paint.setupEditPalette = function (pal) { + var section = newHTML('div', 'section', pal); + section.setAttribute('id', 'painttools'); + var list = ['path', 'ellipse', 'rect', 'tri']; + var i = 0; + for (i = 0; i < list.length; i++) { + var but = newHTML('div', 'element off', section); + var icon = newHTML('div', 'tool ' + list[i] + ' off', but); + icon.setAttribute('key', list[i]); + if (isTablet) { + icon.ontouchstart = Paint.setMode; + } else { + icon.onmousedown = Paint.setMode; + } + } +}; + +Paint.createSizeSelector = function (pal) { + var section = newHTML('div', 'section space', pal); + section.setAttribute('id', 'sizeSelector'); + for (var i = 0; i < Paint.pensizes.length; i++) { + var ps = newHTML('div', 'pensizeholder', section); + ps.key = i; + ps.ontouchstart = function (e) { + e.preventDefault(); + e.stopPropagation(); + var n = Number(this.key); + Paint.strokewidth = Paint.pensizes[Number(this.key)]; + Paint.selectPenSize(n); + }; + var c = newHTML('div', 'line t' + i, ps); + Paint.drawPenSizeInColor(c); + } + Paint.strokewidth = Paint.pensizes[1]; + Paint.selectPenSize(1); +}; + +//////////////////////////////////////// +// Pen sizes +//////////////////////////////////////// + + +Paint.drawPenSizeInColor = function (c) { + c.style.background = Paint.fillcolor; +}; + +Paint.updateStrokes = function () { + var div = gn('sizeSelector'); + if (!div) { + return; + } + for (var i = 0; i < div.childElementCount; i++) { + var elem = div.childNodes[i]; + Paint.drawPenSizeInColor(elem.childNodes[0]); + } +}; + +Paint.selectPenSize = function (str) { + var p = gn('sizeSelector'); + for (var i = 0; i < p.childElementCount; i++) { + var elem = p.childNodes[i]; + if (elem.key == str) { + elem.setAttribute('class', 'pensizeholder on'); + } else { + elem.setAttribute('class', 'pensizeholder off'); + } + } +}; + +///////////////////////////////// +//Right Palette +///////////////////////////////// + +Paint.rightPalette = function (div) { + var rightpal = newHTML('div', 'side', div); + Paint.addSidePalette(rightpal, 'selectortools', ['select', 'rotate']); + Paint.addSidePalette(rightpal, 'edittools', ['stamper', 'scissors']); + Paint.addSidePalette(rightpal, 'filltools', + (iOS.camera == '1' && Camera.available) ? ['camera', 'paintbucket'] : ['paintbucket']); +}; + +Paint.addSidePalette = function (p, id, list) { + var pal = newHTML('div', 'paintpalette short', p); + pal.setAttribute('id', id); + for (var i = 0; i < list.length; i++) { + var but = newHTML('div', 'element off', pal); + var icon = newHTML('div', 'tool ' + list[i] + ' off', but); + icon.setAttribute('key', list[i]); + icon.ontouchstart = Paint.setMode; + } +}; + +Paint.cameraToolsOn = function () { + gn('backdrop').setAttribute('class', 'modal-backdrop fade dark'); + setProps(gn('backdrop').style, { + display: 'block' + }); + var topbar = newHTML('div', 'phototopbar', gn('backdrop')); + topbar.setAttribute('id', 'photocontrols'); + // var actions = newHTML("div",'actions', topbar); + // var buttons = newHTML('div', 'photobuttons', actions); + var fc = newHTML('div', 'flipcamera', topbar); + fc.setAttribute('id', 'cameraflip'); + fc.setAttribute('key', 'cameraflip'); + if (isAndroid && !AndroidInterface.scratchjr_has_multiple_cameras()) { + fc.style.display = 'none'; + } + + fc.ontouchstart = Paint.setMode; + var captureContainer = newHTML('div', 'snapshot-container', gn('backdrop')); + captureContainer.setAttribute('id', 'capture-container'); + var capture = newHTML('div', 'snapshot', captureContainer); + capture.setAttribute('id', 'capture'); + capture.setAttribute('key', 'camerasnap'); + capture.ontouchstart = Paint.setMode; + var cc = newHTML('div', 'cameraclose', topbar); + cc.setAttribute('id', 'cameraclose'); + cc.ontouchstart = Paint.closeCameraMode; +}; + +Paint.closeCameraMode = function () { + ScratchAudio.sndFX('exittap.wav'); + Camera.close(); + Paint.selectButton('select'); +}; + +Paint.cameraToolsOff = function () { + gn('backdrop').setAttribute('class', 'modal-backdrop fade'); + setProps(gn('backdrop').style, { + display: 'none' + }); + if (gn('photocontrols')) { + gn('photocontrols').parentNode.removeChild(gn('photocontrols')); + } + if (gn('capture')) { + var captureContainer = gn('capture').parentNode; + var captureContainerParent = captureContainer.parentNode; + captureContainer.removeChild(gn('capture')); + captureContainerParent.removeChild(gn('capture-container')); + } +}; + +////////////////////////////////// +// canvas Area +////////////////////////////////// + + +Paint.setUpCanvasArea = function () { + var workspace = gn('workspacebkg'); + var dx = Math.floor((workspace.offsetWidth - Paint.workspaceWidth) / 2); + var dy = Math.floor((workspace.offsetHeight - Paint.workspaceHeight) / 2); + var w = Paint.workspaceWidth; + var h = Paint.workspaceHeight; + + var div = gn('maincanvas'); + div.style.background = '#F5F2F7'; + div.style.top = '0px'; + div.style.left = '0px'; + + div.style.width = w + 'px'; + div.style.height = h + 'px'; + div.cx = div.offsetWidth / 2; + div.cy = div.offsetHeight / 2; + div.dx = dx; + div.dy = dy; + + Paint.root.setAttributeNS(null, 'width', w); + Paint.root.setAttributeNS(null, 'height', h); + Paint.drawGrid(w, h); + PaintAction.clearEvents(); +}; + +///////////////////////////////// +//Color Palette +///////////////////////////////// + +Paint.colorPalette = function (div) { + var swatchlist = Paint.initSwatchList(); + var spalContainer = newHTML('div', 'swatchpalette-container', div); + var spal = newHTML('div', 'swatchpalette', spalContainer); + spal.setAttribute('id', 'swatches'); + for (var i = 0; i < swatchlist.length; i++) { + var colour = newHTML('div', 'swatchbucket', spal); + // bucket + var sf = newHTML('div', 'swatchframe', colour); + var sc = newHTML('div', 'swatchcolor', sf); + sc.style.background = swatchlist[i]; + // + sf = newHTML('div', 'splasharea off', colour); + Paint.setSplashColor(sf, Paint.splash, swatchlist[i]); + Paint.addImageUrl(sf, Paint.splashshade); + colour.ontouchstart = Paint.selectSwatch; + } + Paint.setSwatchColor(gn('swatches').childNodes[swatchlist.indexOf('#1C1C1C')]); +}; + +Paint.setSplashColor = function (p, str, color) { + var dataurl = 'data:image/svg+xml;base64,' + btoa(str.replace(/#662D91/g, color)); + Paint.addImageUrl(p, dataurl); +}; + +Paint.addImageUrl = function (p, url) { + var img = document.createElement('img'); + img.src = url; + img.style.position = 'absolute'; + p.appendChild(img); +}; + +Paint.selectSwatch = function (e) { + if (e.touches && (e.touches.length > 1)) { + return; + } + e.preventDefault(); + e.stopPropagation(); + if (Camera.active) { + return; + } + var t; + if (window.event) { + t = window.event.srcElement; + } else { + t = e.target; + } + var b = 'swatchbucket' != t.className; + while (b) { + t = t.parentNode; + b = t && ('swatchbucket' != t.className); + } + if (!t) { + return; + } + ScratchAudio.sndFX('splash.wav'); + Paint.setSwatchColor(t); +}; + +Paint.setSwatchColor = function (t) { + var tools = ['select', 'wand', 'stamper', 'scissors', 'rotate']; + if (t && (tools.indexOf(Paint.mode) > -1)) { + Paint.selectButton('paintbucket'); + } + var c = t.childNodes[0].childNodes[0].style.backgroundColor; + for (var i = 0; i < gn('swatches').childElementCount; i++) { + var mycolor = gn('swatches').childNodes[i].childNodes[0].childNodes[0].style.backgroundColor; + if (c == mycolor) { + gn('swatches').childNodes[i].childNodes[1].setAttribute('class', 'splasharea on'); + } else { + gn('swatches').childNodes[i].childNodes[1].setAttribute('class', 'splasharea off'); + } + } + Paint.fillcolor = c; + Path.quitEditMode(); + Paint.updateStrokes(); +}; + +Paint.initSwatchList = function () { + return [ + // "#FF5500", // new orange + '#FFD2F2', '#FF99D6', '#FF4583', // red pinks + '#C30001', '#FF0023', '#FF8300', '#FFB200', + '#FFF42E', + '#FFF9C2', // pale yellow + '#E2FFBD', // pale green + '#CFF500', // lime green + '#50D823', // problematic + // "#2BFC49", // less problematic + '#29C130', + // "#56C43B", // ERROR? + '#2BBF8A', // new green + '#027607', '#114D24', //greens + '#FFFFFF', '#CCDDE7', '#61787C', '#1C1C1C', // grays + '#D830A3', // sarah's pink shoes border + '#FF64E9', // purple pinks + '#D999FF', ' #A159D3', // vilote + '#722696', // sarah's violet + '#141463', '#003399', '#1D40ED', + '#0079D3', '#009EFF', '#76C8FF', + '#ACE0FD', '#11B7BC', '#21F9F3', '#C3FCFC', '#54311E', + '#8E572A', '#E4B69D', '#FFCDA4', '#FFEDD7' // skin colors + + ]; +}; + +///////////////////////////////////////////////// +// Setup SVG Editor +//////////////////////////////////////////////// + + +Paint.createSVGeditor = function (container) { + var div = newHTML('div', 'maincanvas', container); + div.setAttribute('id', 'maincanvas'); + div.style.background = '#F5F2F7'; + div.style.top = '0px'; + div.style.left = '0px'; + window.onmousemove = undefined; + window.onmouseup = undefined; + Paint.root = SVGTools.create(div); + Paint.root.setAttribute('class', 'active3d'); + xform = Transform.getTranslateTransform(); + selxform = Transform.getTranslateTransform(); + var layer = SVGTools.createGroup(Paint.root, 'layer1'); + layer.setAttribute('style', 'pointer-events:visiblePainted'); + SVGTools.createGroup(Paint.root, 'draglayer'); + SVGTools.createGroup(Paint.root, 'paintgrid'); + gn('paintgrid').setAttribute('opacity', 0.5); +}; + +Paint.clearWorkspace = function () { + var fcn = function (div) { + while (div.childElementCount > 0) { + div.removeChild(div.childNodes[0]); + } + }; + fcn(gn('layer1')); + fcn(gn('paintgrid')); + fcn(gn('draglayer')); + Path.quitEditMode(); +}; + +Paint.drawGrid = function (w, h) { + var attr, path; + if (!Paint.isBkg) { + attr = { + 'd': Paint.getGridPath(w, h, 12), + 'id': getIdFor('gridpath'), + 'opacity': 1, + 'stroke': '#dcddde', + 'fill': 'none', + 'stroke-width': 0.5 + }; + path = SVGTools.addChild(gn('paintgrid'), 'path', attr); + path.setAttribute('style', 'pointer-events:none;'); + } + attr = { + 'd': Paint.getGridPath(w, h, Paint.isBkg ? 24 : 48), + 'id': getIdFor('gridpath'), + 'opacity': 1, + 'stroke': '#c1c2c3', + 'fill': 'none', + 'stroke-width': 0.5 + }; + path = SVGTools.addChild(gn('paintgrid'), 'path', attr); + path.setAttribute('style', 'pointer-events:none;'); +}; + +Paint.getGridPath = function (w, h, gridsize) { + var str = ''; + var dx = gridsize; + // vertical + var cmd; + for (var i = 0; i < w / gridsize; i++) { + cmd = 'M' + dx + ',' + 0 + 'L' + dx + ',' + h; + str += cmd; + dx += gridsize; + } + var dy = gridsize; + // horizontal + for (i = 0; i < h / gridsize; i++) { + cmd = 'M' + 0 + ',' + dy + 'L' + w + ',' + dy; + str += cmd; + dy += gridsize; + } + return str; +}; + + +// Originally PaintIO.js +/////////////////////////// +// Loading and saving +////////////////////////// + +Paint.initBkg = function (ow, oh) { + Paint.nativeJr = true; + Paint.workspaceWidth = ow; + Paint.workspaceHeight = oh; + Paint.setUpCanvasArea(); + var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); + var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); + Paint.setZoomTo(Math.min(dw, dh)); + document.forms.spriteform.style.visibility = 'hidden'; + if (Paint.currentMd5) { + Paint.loadBackground(Paint.currentMd5); + } else { + var attr = { + 'id': 'staticbkg', + 'opacity': 1, + 'fixed': 'yes', + fill: ScratchJr.stagecolor + }; + var cmds = [['M', 0, 0], ['L', 480, 0], ['L', 480, 360], ['L', 0, 360], ['L', 0, 0]]; + attr.d = SVG2Canvas.arrayToString(cmds); + SVGTools.addChild(gn('layer1'), 'path', attr); + Ghost.drawOffscreen(); + PaintUndo.record(true); + } +}; + +Paint.loadBackground = function (md5) { + if (md5.indexOf('samples/') >= 0) { + // Load sample asset + Paint.loadChar(md5); + } else if (!MediaLib.keys[md5]) { + // Load user asset + iOS.getmedia(md5, nextStep); + } else { + // Load library asset + Paint.getBkg(MediaLib.path + md5); + } + function nextStep (base64) { + var str = atob(base64); + IO.getImagesInSVG(str, function () { + Paint.loadBkg(str); + }); + } +}; + +Paint.getBkg = function (url) { + var xmlrequest = new XMLHttpRequest(); + xmlrequest.onreadystatechange = function () { + if (xmlrequest.readyState == 4) { + Paint.createBkgFromXML(xmlrequest.responseText); + } + }; + xmlrequest.open('GET', url, true); + xmlrequest.send(null); +}; + +Paint.loadBkg = function (str) { + Paint.createBkgFromXML(str); +}; + +Paint.createBkgFromXML = function (str) { + Paint.nativeJr = str.indexOf('Scratch Jr') > -1; + str = str.replace(/>\s*<'); + var xmlDoc = new DOMParser().parseFromString(str, 'text/xml'); + var extxml = document.importNode(xmlDoc.documentElement, true); + var flat = Paint.skipUnwantedElements(extxml, []); + for (var i = 0; i < flat.length; i++) { + gn('layer1').appendChild(flat[i]); + if (flat[i].getAttribute('id') == 'fixed') { + flat[i].setAttribute('fixed', 'yes'); + } + flat[i].setAttribute('file', 'yes'); + } + Paint.doAbsolute(gn('layer1')); + if (!Paint.nativeJr) { + Paint.reassingIds(gn('layer1')); + } // make sure there are unique mask names + // gn("layer1").childNodes[0].setAttribute('id', "staticbkg"); + var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); + var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); + Paint.setZoomTo(Math.min(dw, dh)); + PaintUndo.record(true); + if (!Paint.nativeJr) { + Paint.selectButton('paintbucket'); + } +}; + +Paint.initSprite = function (ow, oh) { + Paint.nativeJr = true; + document.forms.spriteform.style.visibility = 'visible'; + document.forms.spriteform.name.value = gn(Paint.currentName) ? gn(Paint.currentName).owner.name : Paint.currentName; + if (ow) { + Paint.workspaceWidth = ow; + } + if (oh) { + Paint.workspaceHeight = oh; + } + if (Paint.currentMd5) { + Paint.loadCharacter(Paint.currentMd5); + } else { + Paint.setUpCanvasArea(); + setCanvasSize( + Ghost.maskCanvas, + Math.round(Number(Paint.root.getAttribute('width')) * Paint.currentZoom), + Math.round(Number(Paint.root.getAttribute('height')) * Paint.currentZoom) + ); + var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); + var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); + Paint.setZoomTo(Math.min(dw, dh)); + PaintUndo.record(true); + } +}; + +Paint.loadCharacter = function (md5) { + if (md5.indexOf('samples/') >= 0) { + // Load sample asset + Paint.loadChar(md5); + } else if (!MediaLib.keys[md5]) { + // Load user asset + iOS.getmedia(md5, nextStep); + } else { + // Load library asset + Paint.loadChar(MediaLib.path + md5); + } + function nextStep (base64) { + var str = atob(base64); + IO.getImagesInSVG(str, function () { + Paint.loadSprite(str); + }); + } +}; + +Paint.loadSprite = function (svg) { + Paint.createCharFromXML(svg, Paint.currentName); +}; + +Paint.loadChar = function (url) { + var xmlrequest = new XMLHttpRequest(); + xmlrequest.onreadystatechange = function () { + if (xmlrequest.readyState == 4) { + Paint.createCharFromXML(xmlrequest.responseText, Paint.currentName); + } + }; + xmlrequest.open('GET', url, true); + xmlrequest.send(null); +}; + +Paint.adjustShapePosition = function (dx, dy) { + xform.setTranslate(dx, dy); + Transform.translateTo(gn('layer1'), xform); +}; + +/////////////////////////////////// +// Saving +///////////////////////////////// + +Paint.savePageImage = function (fcn) { + var worthsaving = (gn('layer1').childElementCount > 0); + if (!worthsaving) { + Paint.close(); + } else { + Paint.saving = true; + if (fcn) { + Alert.open(Paint.frame, gn('donecheck'), Localization.localize('ALERT_SAVING'), '#28A5DA'); + Alert.balloon.style.zIndex = 12000; + } + Paint.svgdata = SVGTools.saveBackground(gn('layer1'), Paint.workspaceWidth, Paint.workspaceHeight); + IO.setMedia(Paint.svgdata, 'svg', function (str) { + Paint.changeBackground(str, fcn); + }); + } +}; + +Paint.changeBackground = function (md5, fcn) { + Paint.saveMD5 = md5; + var type = 'userbkgs'; + var mobj = {}; + mobj.cond = 'md5 = ? AND version = ?'; + mobj.items = ['*']; + mobj.values = [Paint.saveMD5, ScratchJr.version]; + IO.query(type, mobj, function (str) { + Paint.checkDuplicateBkg(str, fcn); + }); +}; + +Paint.checkDuplicateBkg = function (str, fcn) { + var list = JSON.parse(str); + if (list.length > 0) { + if (fcn) { + fcn('duplicate'); + } + } else { + Paint.addToBkgLib(fcn); + } +}; + +///////////////////////////////////// +// userbkgs: stores backgrounds +///////////////////////////////////// +/* + [version] => + [md5] => + [altmd5] => //for PNG option + [ext] => png / svg + [width] => + [height] => +*/ + +Paint.addToBkgLib = function (fcn) { + var dataurl = IO.getThumbnail(Paint.svgdata, 480, 360, 120, 90); + var pngBase64 = dataurl.split(',')[1]; + iOS.setmedia(pngBase64, 'png', setBkgRecord); + function setBkgRecord (pngmd5) { + var json = {}; + var keylist = ['md5', 'altmd5', 'version', 'width', 'height', 'ext']; + var values = '?,?,?,?,?,?'; + json.values = [Paint.saveMD5, pngmd5, ScratchJr.version, '480', '360', 'svg']; + json.stmt = 'insert into userbkgs (' + keylist.toString() + ') values (' + values + ')'; + iOS.stmt(json, fcn); + } +}; + +Paint.changePage = function () { + ScratchJr.stage.currentPage.setBackground(Paint.saveMD5, ScratchJr.stage.currentPage.updateBkg); + Paint.close(); +}; + +Paint.saveSprite = function (fcn) { + var cname = document.forms.spriteform.name.value; + var worthsaving = (gn('layer1').childElementCount > 0) && (PaintUndo.index > 0); + if (worthsaving) { + Paint.saving = true; + if (fcn) { + Alert.open(Paint.frame, gn('donecheck'), 'Saving...', '#28A5DA'); + Alert.balloon.style.zIndex = 12000; + } + Paint.svgdata = SVGTools.saveShape(gn('layer1'), Paint.workspaceWidth, Paint.workspaceHeight); + IO.setMedia(Paint.svgdata, 'svg', function (str) { + Paint.addOrModifySprite(str, fcn); + }); + } else { + var type = Paint.getLoadType(Paint.spriteId, cname); + if ((cname != Paint.currentName) && (type == 'modify')) { + ScratchJr.stage.currentPage.modifySpriteName(cname, Paint.spriteId); + } else if (Paint.currentMd5 && (type == 'add')) { + ScratchJr.stage.currentPage.addSprite(Paint.costumeScale, Paint.currentMd5, cname); + } + Paint.close(); + } +}; + +Paint.addOrModifySprite = function (str, fcn) { + Paint.saveMD5 = str; + var mobj = {}; + mobj.cond = 'md5 = ? AND version = ?'; + mobj.items = ['*']; + mobj.values = [Paint.saveMD5, ScratchJr.version]; + IO.query('usershapes', mobj, function (str) { + Paint.checkDuplicate(str, fcn); + }); +}; + +Paint.checkDuplicate = function (str, fcn) { + var list = JSON.parse(str); + if (list.length > 0) { + if (fcn) { + fcn('duplicate'); + } + } else { + Paint.addToLib(fcn); + } +}; + +///////////////////////////////////// +// usershapes: stores costumes +///////////////////////////////////// +/* current data + [md5] => + [altmd5] => // for PNG -- not used + [version] => + [scale] => + [ext] => png / svg + [width] => + [height] => + [name] => + +*/ + +Paint.addToLib = function (fcn) { + var scale = '0.5'; // always saves with 1/2 the size + var cname = document.forms.spriteform.name.value; + cname = ((unescape(cname)).replace(/[0-9]/g, '')).replace(/\s*/g, ''); + var box = SVGTools.getBox(gn('layer1')).rounded(); + box = box.expandBy(20); + var w = box.width.toString(); + var h = box.height.toString(); + var dataurl = IO.getThumbnail(Paint.svgdata, w, h, 120, 90); + var pngBase64 = dataurl.split(',')[1]; + iOS.setmedia(pngBase64, 'png', setCostumeRecord); + function setCostumeRecord (pngmd5) { + var json = {}; + var keylist = ['scale', 'md5', 'altmd5', 'version', 'width', 'height', 'ext', 'name']; + var values = '?,?,?,?,?,?,?,?'; + json.values = [scale, Paint.saveMD5, pngmd5, ScratchJr.version, w, h, 'svg', cname]; + json.stmt = 'insert into usershapes (' + keylist.toString() + ') values (' + values + ')'; + iOS.stmt(json, fcn); + } +}; + +Paint.changePageSprite = function () { + Paint.close(); + var cname = document.forms.spriteform.name.value; + var type = Paint.getLoadType(Paint.spriteId, cname); + switch (type) { + case 'modify': + ScratchJr.stage.currentPage.modifySprite(Paint.saveMD5, cname, Paint.spriteId); + break; + case 'add': + ScratchJr.stage.currentPage.addSprite(Paint.costumeScale, Paint.saveMD5, cname); + break; + default: + ScratchJr.stage.currentPage.update(); + break; + } +}; + +Paint.getLoadType = function (sid, cid) { + if (!cid) { + return 'none'; + } + if (sid && cid) { + return 'modify'; + } + return 'add'; +}; + +/////////////////////////// +// XML import processs +/////////////////////////// + +Paint.skipUnwantedElements = function (p, res) { + for (var i = 0; i < p.childNodes.length; i++) { + var elem = p.childNodes[i]; + if (elem.nodeName == 'metadata') { + continue; + } + if (elem.nodeName == 'defs') { + continue; + } + if (elem.nodeName == 'sodipodi:namedview') { + continue; + } + if (elem.nodeName == '#comment') { + continue; + } + if ((elem.nodeName == 'g') && (elem.id == 'layer1')) { + Paint.skipUnwantedElements(elem, res); + if (elem.removeAttribute('id')) { + elem.removeAttribute('id'); + } + } else { + res.push(elem); + } + } + return res; +}; + +Paint.reassingIds = function (p) { + for (var i = 0; i < p.childNodes.length; i++) { + var elem = p.childNodes[i]; + if (elem.parentNode.getAttribute('fixed') == 'yes') { + elem.setAttribute('fixed', 'yes'); + } + var id = elem.getAttribute('id'); + if (!id) { + elem.setAttribute('id', getIdFor(elem.nodeName)); + } + if (elem.nodeName == 'g') { + Paint.reassingIds(elem); + } + } +}; + +Paint.createCharFromXML = function (str) { + Paint.nativeJr = str.indexOf('Scratch Jr') > -1; + var dx = (Paint.workspaceWidth < 432) ? Math.floor((432 - Paint.workspaceWidth) / 2) : 0; + var dy = (Paint.workspaceHeight < 384) ? Math.floor((384 - Paint.workspaceHeight) / 2) : 0; + if (Paint.workspaceWidth < 432) { + Paint.workspaceWidth = 432; + } + if (Paint.workspaceHeight < 384) { + Paint.workspaceHeight = 384; + } + Paint.setUpCanvasArea(); + str = str.replace(/>\s*<'); + var xmlDoc = new DOMParser().parseFromString(str, 'text/xml'); + var extxml = document.importNode(xmlDoc.documentElement, true); + var flat = Paint.skipUnwantedElements(extxml, []); + for (var i = 0; i < flat.length; i++) { + gn('layer1').appendChild(flat[i]); + } + Paint.doAbsolute(gn('layer1')); + Paint.adjustShapePosition(dx, dy); + if (!Paint.nativeJr) { + Paint.reassingIds(gn('layer1')); + } // make sure there are unique mask names + Paint.scaleToFit(); + Paint.minZoom = Paint.currentZoom < 1 ? Paint.currentZoom / 2 : 1; + var maxpix = 2290 * 2289; // Magic iOS max canvas size + var ratio = maxpix / (Paint.workspaceWidth * Paint.workspaceHeight); + var zoom = Math.floor(Math.sqrt(ratio)); + if (zoom < Paint.maxZoom) { + Paint.maxZoom = zoom; + } + PaintUndo.record(true); + if (!Paint.nativeJr) { + Paint.selectButton('paintbucket'); + } +}; + +Paint.doAbsolute = function (div) { + for (var i = 0; i < div.childElementCount; i++) { + var elem = div.childNodes[i]; + if (elem.tagName == 'path') { + SVG2Canvas.setAbsolutePath(elem); + } + if (elem.tagName == 'g') { + Paint.doAbsolute(div.childNodes[i]); + } + } +}; + +Paint.getComponents = function (p, res) { + for (var i = 0; i < p.childNodes.length; i++) { + var elem = p.childNodes[i]; + if (elem.nodeName == 'metadata') { + continue; + } + if (elem.nodeName == 'defs') { + continue; + } + if (elem.nodeName == 'sodipodi:namedview') { + continue; + } + if (elem.nodeName == '#comment') { + continue; + } + if (elem.nodeName == 'g') { + Paint.getComponents(elem, res); + if (elem.getAttribute('id')) { + elem.removeAttribute('id'); + } + } else { + res.push(elem); + } + } + return res; +}; diff --git a/src/painteditor/PaintIO.js b/src/painteditor/PaintIO.js deleted file mode 100644 index 494758c..0000000 --- a/src/painteditor/PaintIO.js +++ /dev/null @@ -1,462 +0,0 @@ -/////////////////////////// -// Loading and saving -////////////////////////// - -Paint.initBkg = function (ow, oh) { - Paint.nativeJr = true; - Paint.workspaceWidth = ow; - Paint.workspaceHeight = oh; - Paint.setUpCanvasArea(); - var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); - var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); - Paint.setZoomTo(Math.min(dw, dh)); - document.forms.spriteform.style.visibility = 'hidden'; - if (Paint.currentMd5) { - Paint.loadBackground(Paint.currentMd5); - } else { - var attr = { - 'id': 'staticbkg', - 'opacity': 1, - 'fixed': 'yes', - fill: ScratchJr.stagecolor - }; - var cmds = [['M', 0, 0], ['L', 480, 0], ['L', 480, 360], ['L', 0, 360], ['L', 0, 0]]; - attr.d = SVG2Canvas.arrayToString(cmds); - SVGTools.addChild(gn('layer1'), 'path', attr); - Ghost.drawOffscreen(); - PaintUndo.record(true); - } -}; - -Paint.loadBackground = function (md5) { - if (md5.indexOf('samples/') >= 0) { - // Load sample asset - Paint.loadChar(md5); - } else if (!MediaLib.keys[md5]) { - // Load user asset - iOS.getmedia(md5, nextStep); - } else { - // Load library asset - Paint.getBkg(MediaLib.path + md5); - } - function nextStep (base64) { - var str = atob(base64); - IO.getImagesInSVG(str, function () { - Paint.loadBkg(str); - }); - } -}; - -Paint.getBkg = function (url) { - var xmlrequest = new XMLHttpRequest(); - xmlrequest.onreadystatechange = function () { - if (xmlrequest.readyState == 4) { - Paint.createBkgFromXML(xmlrequest.responseText); - } - }; - xmlrequest.open('GET', url, true); - xmlrequest.send(null); -}; - -Paint.loadBkg = function (str) { - Paint.createBkgFromXML(str); -}; - -Paint.createBkgFromXML = function (str) { - Paint.nativeJr = str.indexOf('Scratch Jr') > -1; - str = str.replace(/>\s*<'); - var xmlDoc = new DOMParser().parseFromString(str, 'text/xml'); - var extxml = document.importNode(xmlDoc.documentElement, true); - var flat = Paint.skipUnwantedElements(extxml, []); - for (var i = 0; i < flat.length; i++) { - gn('layer1').appendChild(flat[i]); - if (flat[i].getAttribute('id') == 'fixed') { - flat[i].setAttribute('fixed', 'yes'); - } - flat[i].setAttribute('file', 'yes'); - } - Paint.doAbsolute(gn('layer1')); - if (!Paint.nativeJr) { - Paint.reassingIds(gn('layer1')); - } // make sure there are unique mask names - // gn("layer1").childNodes[0].setAttribute('id', "staticbkg"); - var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); - var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); - Paint.setZoomTo(Math.min(dw, dh)); - PaintUndo.record(true); - if (!Paint.nativeJr) { - Paint.selectButton('paintbucket'); - } -}; - -Paint.initSprite = function (ow, oh) { - Paint.nativeJr = true; - document.forms.spriteform.style.visibility = 'visible'; - document.forms.spriteform.name.value = gn(Paint.currentName) ? gn(Paint.currentName).owner.name : Paint.currentName; - if (ow) { - Paint.workspaceWidth = ow; - } - if (oh) { - Paint.workspaceHeight = oh; - } - if (Paint.currentMd5) { - Paint.loadCharacter(Paint.currentMd5); - } else { - Paint.setUpCanvasArea(); - setCanvasSize( - Ghost.maskCanvas, - Math.round(Number(Paint.root.getAttribute('width')) * Paint.currentZoom), - Math.round(Number(Paint.root.getAttribute('height')) * Paint.currentZoom) - ); - var dh = Paint.root.parentNode.parentNode.offsetHeight / (Paint.workspaceHeight + 10); - var dw = Paint.root.parentNode.parentNode.offsetWidth / (Paint.workspaceWidth + 10); - Paint.setZoomTo(Math.min(dw, dh)); - PaintUndo.record(true); - } -}; - -Paint.loadCharacter = function (md5) { - if (md5.indexOf('samples/') >= 0) { - // Load sample asset - Paint.loadChar(md5); - } else if (!MediaLib.keys[md5]) { - // Load user asset - iOS.getmedia(md5, nextStep); - } else { - // Load library asset - Paint.loadChar(MediaLib.path + md5); - } - function nextStep (base64) { - var str = atob(base64); - IO.getImagesInSVG(str, function () { - Paint.loadSprite(str); - }); - } -}; - -Paint.loadSprite = function (svg) { - Paint.createCharFromXML(svg, Paint.currentName); -}; - -Paint.loadChar = function (url) { - var xmlrequest = new XMLHttpRequest(); - xmlrequest.onreadystatechange = function () { - if (xmlrequest.readyState == 4) { - Paint.createCharFromXML(xmlrequest.responseText, Paint.currentName); - } - }; - xmlrequest.open('GET', url, true); - xmlrequest.send(null); -}; - -Paint.adjustShapePosition = function (dx, dy) { - xform.setTranslate(dx, dy); - Transform.translateTo(gn('layer1'), xform); -}; - -/////////////////////////////////// -// Saving -///////////////////////////////// - -Paint.savePageImage = function (fcn) { - var worthsaving = (gn('layer1').childElementCount > 0); - if (!worthsaving) { - Paint.close(); - } else { - Paint.saving = true; - if (fcn) { - Alert.open(Paint.frame, gn('donecheck'), Localization.localize('ALERT_SAVING'), '#28A5DA'); - Alert.balloon.style.zIndex = 12000; - } - Paint.svgdata = SVGTools.saveBackground(gn('layer1'), Paint.workspaceWidth, Paint.workspaceHeight); - IO.setMedia(Paint.svgdata, 'svg', function (str) { - Paint.changeBackground(str, fcn); - }); - } -}; - -Paint.changeBackground = function (md5, fcn) { - Paint.saveMD5 = md5; - var type = 'userbkgs'; - var mobj = {}; - mobj.cond = 'md5 = ? AND version = ?'; - mobj.items = ['*']; - mobj.values = [Paint.saveMD5, ScratchJr.version]; - IO.query(type, mobj, function (str) { - Paint.checkDuplicateBkg(str, fcn); - }); -}; - -Paint.checkDuplicateBkg = function (str, fcn) { - var list = JSON.parse(str); - if (list.length > 0) { - if (fcn) { - fcn('duplicate'); - } - } else { - Paint.addToBkgLib(fcn); - } -}; - -///////////////////////////////////// -// userbkgs: stores backgrounds -///////////////////////////////////// -/* - [version] => - [md5] => - [altmd5] => //for PNG option - [ext] => png / svg - [width] => - [height] => -*/ - -Paint.addToBkgLib = function (fcn) { - var dataurl = IO.getThumbnail(Paint.svgdata, 480, 360, 120, 90); - var pngBase64 = dataurl.split(',')[1]; - iOS.setmedia(pngBase64, 'png', setBkgRecord); - function setBkgRecord (pngmd5) { - var json = {}; - var keylist = ['md5', 'altmd5', 'version', 'width', 'height', 'ext']; - var values = '?,?,?,?,?,?'; - json.values = [Paint.saveMD5, pngmd5, ScratchJr.version, '480', '360', 'svg']; - json.stmt = 'insert into userbkgs (' + keylist.toString() + ') values (' + values + ')'; - iOS.stmt(json, fcn); - } -}; - -Paint.changePage = function () { - ScratchJr.stage.currentPage.setBackground(Paint.saveMD5, ScratchJr.stage.currentPage.updateBkg); - Paint.close(); -}; - -Paint.saveSprite = function (fcn) { - var cname = document.forms.spriteform.name.value; - var worthsaving = (gn('layer1').childElementCount > 0) && (PaintUndo.index > 0); - if (worthsaving) { - Paint.saving = true; - if (fcn) { - Alert.open(Paint.frame, gn('donecheck'), 'Saving...', '#28A5DA'); - Alert.balloon.style.zIndex = 12000; - } - Paint.svgdata = SVGTools.saveShape(gn('layer1'), Paint.workspaceWidth, Paint.workspaceHeight); - IO.setMedia(Paint.svgdata, 'svg', function (str) { - Paint.addOrModifySprite(str, fcn); - }); - } else { - var type = Paint.getLoadType(Paint.spriteId, cname); - if ((cname != Paint.currentName) && (type == 'modify')) { - ScratchJr.stage.currentPage.modifySpriteName(cname, Paint.spriteId); - } else if (Paint.currentMd5 && (type == 'add')) { - ScratchJr.stage.currentPage.addSprite(Paint.costumeScale, Paint.currentMd5, cname); - } - Paint.close(); - } -}; - -Paint.addOrModifySprite = function (str, fcn) { - Paint.saveMD5 = str; - var mobj = {}; - mobj.cond = 'md5 = ? AND version = ?'; - mobj.items = ['*']; - mobj.values = [Paint.saveMD5, ScratchJr.version]; - IO.query('usershapes', mobj, function (str) { - Paint.checkDuplicate(str, fcn); - }); -}; - -Paint.checkDuplicate = function (str, fcn) { - var list = JSON.parse(str); - if (list.length > 0) { - if (fcn) { - fcn('duplicate'); - } - } else { - Paint.addToLib(fcn); - } -}; - -///////////////////////////////////// -// usershapes: stores costumes -///////////////////////////////////// -/* current data - [md5] => - [altmd5] => // for PNG -- not used - [version] => - [scale] => - [ext] => png / svg - [width] => - [height] => - [name] => - -*/ - -Paint.addToLib = function (fcn) { - var scale = '0.5'; // always saves with 1/2 the size - var cname = document.forms.spriteform.name.value; - cname = ((unescape(cname)).replace(/[0-9]/g, '')).replace(/\s*/g, ''); - var box = SVGTools.getBox(gn('layer1')).rounded(); - box = box.expandBy(20); - var w = box.width.toString(); - var h = box.height.toString(); - var dataurl = IO.getThumbnail(Paint.svgdata, w, h, 120, 90); - var pngBase64 = dataurl.split(',')[1]; - iOS.setmedia(pngBase64, 'png', setCostumeRecord); - function setCostumeRecord (pngmd5) { - var json = {}; - var keylist = ['scale', 'md5', 'altmd5', 'version', 'width', 'height', 'ext', 'name']; - var values = '?,?,?,?,?,?,?,?'; - json.values = [scale, Paint.saveMD5, pngmd5, ScratchJr.version, w, h, 'svg', cname]; - json.stmt = 'insert into usershapes (' + keylist.toString() + ') values (' + values + ')'; - iOS.stmt(json, fcn); - } -}; - -Paint.changePageSprite = function () { - Paint.close(); - var cname = document.forms.spriteform.name.value; - var type = Paint.getLoadType(Paint.spriteId, cname); - switch (type) { - case 'modify': - ScratchJr.stage.currentPage.modifySprite(Paint.saveMD5, cname, Paint.spriteId); - break; - case 'add': - ScratchJr.stage.currentPage.addSprite(Paint.costumeScale, Paint.saveMD5, cname); - break; - default: - ScratchJr.stage.currentPage.update(); - break; - } -}; - -Paint.getLoadType = function (sid, cid) { - if (!cid) { - return 'none'; - } - if (sid && cid) { - return 'modify'; - } - return 'add'; -}; - -/////////////////////////// -// XML import processs -/////////////////////////// - -Paint.skipUnwantedElements = function (p, res) { - for (var i = 0; i < p.childNodes.length; i++) { - var elem = p.childNodes[i]; - if (elem.nodeName == 'metadata') { - continue; - } - if (elem.nodeName == 'defs') { - continue; - } - if (elem.nodeName == 'sodipodi:namedview') { - continue; - } - if (elem.nodeName == '#comment') { - continue; - } - if ((elem.nodeName == 'g') && (elem.id == 'layer1')) { - Paint.skipUnwantedElements(elem, res); - if (elem.removeAttribute('id')) { - elem.removeAttribute('id'); - } - } else { - res.push(elem); - } - } - return res; -}; - -Paint.reassingIds = function (p) { - for (var i = 0; i < p.childNodes.length; i++) { - var elem = p.childNodes[i]; - if (elem.parentNode.getAttribute('fixed') == 'yes') { - elem.setAttribute('fixed', 'yes'); - } - var id = elem.getAttribute('id'); - if (!id) { - elem.setAttribute('id', getIdFor(elem.nodeName)); - } - if (elem.nodeName == 'g') { - Paint.reassingIds(elem); - } - } -}; - -Paint.createCharFromXML = function (str) { - Paint.nativeJr = str.indexOf('Scratch Jr') > -1; - var dx = (Paint.workspaceWidth < 432) ? Math.floor((432 - Paint.workspaceWidth) / 2) : 0; - var dy = (Paint.workspaceHeight < 384) ? Math.floor((384 - Paint.workspaceHeight) / 2) : 0; - if (Paint.workspaceWidth < 432) { - Paint.workspaceWidth = 432; - } - if (Paint.workspaceHeight < 384) { - Paint.workspaceHeight = 384; - } - Paint.setUpCanvasArea(); - str = str.replace(/>\s*<'); - var xmlDoc = new DOMParser().parseFromString(str, 'text/xml'); - var extxml = document.importNode(xmlDoc.documentElement, true); - var flat = Paint.skipUnwantedElements(extxml, []); - for (var i = 0; i < flat.length; i++) { - gn('layer1').appendChild(flat[i]); - } - Paint.doAbsolute(gn('layer1')); - Paint.adjustShapePosition(dx, dy); - if (!Paint.nativeJr) { - Paint.reassingIds(gn('layer1')); - } // make sure there are unique mask names - Paint.scaleToFit(); - Paint.minZoom = Paint.currentZoom < 1 ? Paint.currentZoom / 2 : 1; - var maxpix = 2290 * 2289; // Magic iOS max canvas size - var ratio = maxpix / (Paint.workspaceWidth * Paint.workspaceHeight); - var zoom = Math.floor(Math.sqrt(ratio)); - if (zoom < Paint.maxZoom) { - Paint.maxZoom = zoom; - } - PaintUndo.record(true); - if (!Paint.nativeJr) { - Paint.selectButton('paintbucket'); - } -}; - -Paint.doAbsolute = function (div) { - for (var i = 0; i < div.childElementCount; i++) { - var elem = div.childNodes[i]; - if (elem.tagName == 'path') { - SVG2Canvas.setAbsolutePath(elem); - } - if (elem.tagName == 'g') { - Paint.doAbsolute(div.childNodes[i]); - } - } -}; - -Paint.getComponents = function (p, res) { - for (var i = 0; i < p.childNodes.length; i++) { - var elem = p.childNodes[i]; - if (elem.nodeName == 'metadata') { - continue; - } - if (elem.nodeName == 'defs') { - continue; - } - if (elem.nodeName == 'sodipodi:namedview') { - continue; - } - if (elem.nodeName == '#comment') { - continue; - } - if (elem.nodeName == 'g') { - Paint.getComponents(elem, res); - if (elem.getAttribute('id')) { - elem.removeAttribute('id'); - } - } else { - res.push(elem); - } - } - return res; -}; diff --git a/src/painteditor/PaintLayout.js b/src/painteditor/PaintLayout.js deleted file mode 100644 index a970317..0000000 --- a/src/painteditor/PaintLayout.js +++ /dev/null @@ -1,491 +0,0 @@ -///////////////////////////////// -//Layout Setup -///////////////////////////////// - -Paint.layout = function () { - Paint.topbar(); - var div = newHTML('div', 'innerpaint', Paint.frame); - Paint.leftPalette(div); - var workspaceContainer = newHTML('div', 'workspacebkg-container', div); - var workspace = newHTML('div', 'workspacebkg', workspaceContainer); - workspace.setAttribute('id', 'workspacebkg'); - Paint.rightPalette(div); - Paint.colorPalette(Paint.frame); - Paint.selectButton('path'); - Paint.createSVGeditor(workspace); -}; - -///////////////////////////////// -//top bar -///////////////////////////////// - -Paint.topbar = function () { - var pt = newHTML('div', 'paintop', Paint.frame); - Paint.checkMark(pt); - PaintUndo.setup(pt); // plug here the undo - Paint.nameOfcostume(pt); -}; - -Paint.checkMark = function (pt) { - var clicky = newHTML('div', 'paintdone', pt); - clicky.id = 'donecheck'; - if (isTablet) { - clicky.ontouchstart = Paint.backToProject; - } else { - clicky.onmousedown = Paint.backToProject; - } -}; - -Paint.nameOfcostume = function (p) { - var sform = newHTML('form', 'spriteform', p); - sform.name = 'spriteform'; - var ti = newHTML('input', undefined, sform); - ti.onkeypress = undefined; - ti.autocomplete = 'off'; - ti.autocorrect = false; - ti.name = 'name'; - ti.maxLength = 25; - ti.firstTime = true; - ti.onfocus = Paint.nameFocus; - ti.onblur = Paint.nameBlur; - ti.onkeypress = Paint.handleNamePress; - ti.onkeyup = Paint.handleKeyRelease; - sform.onsubmit = Paint.submitNameChange; -}; - -Paint.submitNameChange = function (e) { - e.preventDefault(); - var input = e.target; - input.blur(); -}; - -Paint.nameFocus = function (e) { - e.preventDefault(); - e.stopPropagation(); - var ti = e.target; - ti.firstTime = true; - ScratchJr.activeFocus = ti; - if (isAndroid) { - AndroidInterface.scratchjr_setsoftkeyboardscrolllocation( - ti.getBoundingClientRect().top * window.devicePixelRatio, - ti.getBoundingClientRect().bottom * window.devicePixelRatio - ); - } - Undo.aux = Project.getProject(ScratchJr.stage.currentPage.id); - setTimeout(function () { - ti.setSelectionRange(ti.value.length, ti.value.length); - }, 1); -}; - -Paint.nameBlur = function (e) { - ScratchJr.activeFocus = undefined; - var spr = ScratchJr.getSprite(); - var ti = e.target; - var val = ScratchJr.validate(ti.value, spr.name); - ti.value = val.substring(0, ti.maxLength); - ScratchJr.storyStart('Paint.nameBlur'); -}; - -Paint.handleNamePress = function (e) { - var key = e.keyCode || e.which; - if (key == 13) { - Paint.submitNameChange(e); - } else { - var ti = e.target; - if (ti.firstTime) { - ti.firstTime = false; - ti.value = ''; - } - if (ti.value.length == 25) { - ScratchAudio.sndFX('boing.wav'); - } - } -}; - -Paint.handleKeyRelease = function (e) { - var key = e.keyCode || e.which; - var ti = e.target; - if (key != 8) { - return; - } - if (ti.firstTime) { - ti.firstTime = false; - ti.value = ''; - } -}; - -///////////////////////////////// -//Left Palette -///////////////////////////////// - -Paint.leftPalette = function (div) { - var leftpal = newHTML('div', 'side up', div); - var pal = newHTML('div', 'paintpalette', leftpal); - pal.setAttribute('id', 'paintpalette'); - Paint.setupEditPalette(pal); - Paint.createSizeSelector(pal); -}; - -Paint.setupEditPalette = function (pal) { - var section = newHTML('div', 'section', pal); - section.setAttribute('id', 'painttools'); - var list = ['path', 'ellipse', 'rect', 'tri']; - var i = 0; - for (i = 0; i < list.length; i++) { - var but = newHTML('div', 'element off', section); - var icon = newHTML('div', 'tool ' + list[i] + ' off', but); - icon.setAttribute('key', list[i]); - if (isTablet) { - icon.ontouchstart = Paint.setMode; - } else { - icon.onmousedown = Paint.setMode; - } - } -}; - -Paint.createSizeSelector = function (pal) { - var section = newHTML('div', 'section space', pal); - section.setAttribute('id', 'sizeSelector'); - for (var i = 0; i < Paint.pensizes.length; i++) { - var ps = newHTML('div', 'pensizeholder', section); - ps.key = i; - ps.ontouchstart = function (e) { - e.preventDefault(); - e.stopPropagation(); - var n = Number(this.key); - Paint.strokewidth = Paint.pensizes[Number(this.key)]; - Paint.selectPenSize(n); - }; - var c = newHTML('div', 'line t' + i, ps); - Paint.drawPenSizeInColor(c); - } - Paint.strokewidth = Paint.pensizes[1]; - Paint.selectPenSize(1); -}; - -//////////////////////////////////////// -// Pen sizes -//////////////////////////////////////// - - -Paint.drawPenSizeInColor = function (c) { - c.style.background = Paint.fillcolor; -}; - -Paint.updateStrokes = function () { - var div = gn('sizeSelector'); - if (!div) { - return; - } - for (var i = 0; i < div.childElementCount; i++) { - var elem = div.childNodes[i]; - Paint.drawPenSizeInColor(elem.childNodes[0]); - } -}; - -Paint.selectPenSize = function (str) { - var p = gn('sizeSelector'); - for (var i = 0; i < p.childElementCount; i++) { - var elem = p.childNodes[i]; - if (elem.key == str) { - elem.setAttribute('class', 'pensizeholder on'); - } else { - elem.setAttribute('class', 'pensizeholder off'); - } - } -}; - -///////////////////////////////// -//Right Palette -///////////////////////////////// - -Paint.rightPalette = function (div) { - var rightpal = newHTML('div', 'side', div); - Paint.addSidePalette(rightpal, 'selectortools', ['select', 'rotate']); - Paint.addSidePalette(rightpal, 'edittools', ['stamper', 'scissors']); - Paint.addSidePalette(rightpal, 'filltools', - (iOS.camera == '1' && Camera.available) ? ['camera', 'paintbucket'] : ['paintbucket']); -}; - -Paint.addSidePalette = function (p, id, list) { - var pal = newHTML('div', 'paintpalette short', p); - pal.setAttribute('id', id); - for (var i = 0; i < list.length; i++) { - var but = newHTML('div', 'element off', pal); - var icon = newHTML('div', 'tool ' + list[i] + ' off', but); - icon.setAttribute('key', list[i]); - icon.ontouchstart = Paint.setMode; - } -}; - -Paint.cameraToolsOn = function () { - gn('backdrop').setAttribute('class', 'modal-backdrop fade dark'); - setProps(gn('backdrop').style, { - display: 'block' - }); - var topbar = newHTML('div', 'phototopbar', gn('backdrop')); - topbar.setAttribute('id', 'photocontrols'); - // var actions = newHTML("div",'actions', topbar); - // var buttons = newHTML('div', 'photobuttons', actions); - var fc = newHTML('div', 'flipcamera', topbar); - fc.setAttribute('id', 'cameraflip'); - fc.setAttribute('key', 'cameraflip'); - if (isAndroid && !AndroidInterface.scratchjr_has_multiple_cameras()) { - fc.style.display = 'none'; - } - - fc.ontouchstart = Paint.setMode; - var captureContainer = newHTML('div', 'snapshot-container', gn('backdrop')); - captureContainer.setAttribute('id', 'capture-container'); - var capture = newHTML('div', 'snapshot', captureContainer); - capture.setAttribute('id', 'capture'); - capture.setAttribute('key', 'camerasnap'); - capture.ontouchstart = Paint.setMode; - var cc = newHTML('div', 'cameraclose', topbar); - cc.setAttribute('id', 'cameraclose'); - cc.ontouchstart = Paint.closeCameraMode; -}; - -Paint.closeCameraMode = function () { - ScratchAudio.sndFX('exittap.wav'); - Camera.close(); - Paint.selectButton('select'); -}; - -Paint.cameraToolsOff = function () { - gn('backdrop').setAttribute('class', 'modal-backdrop fade'); - setProps(gn('backdrop').style, { - display: 'none' - }); - if (gn('photocontrols')) { - gn('photocontrols').parentNode.removeChild(gn('photocontrols')); - } - if (gn('capture')) { - var captureContainer = gn('capture').parentNode; - var captureContainerParent = captureContainer.parentNode; - captureContainer.removeChild(gn('capture')); - captureContainerParent.removeChild(gn('capture-container')); - } -}; - -////////////////////////////////// -// canvas Area -////////////////////////////////// - - -Paint.setUpCanvasArea = function () { - var workspace = gn('workspacebkg'); - var dx = Math.floor((workspace.offsetWidth - Paint.workspaceWidth) / 2); - var dy = Math.floor((workspace.offsetHeight - Paint.workspaceHeight) / 2); - var w = Paint.workspaceWidth; - var h = Paint.workspaceHeight; - - var div = gn('maincanvas'); - div.style.background = '#F5F2F7'; - div.style.top = '0px'; - div.style.left = '0px'; - - div.style.width = w + 'px'; - div.style.height = h + 'px'; - div.cx = div.offsetWidth / 2; - div.cy = div.offsetHeight / 2; - div.dx = dx; - div.dy = dy; - - Paint.root.setAttributeNS(null, 'width', w); - Paint.root.setAttributeNS(null, 'height', h); - Paint.drawGrid(w, h); - PaintAction.clearEvents(); -}; - -///////////////////////////////// -//Color Palette -///////////////////////////////// - -Paint.colorPalette = function (div) { - var swatchlist = Paint.initSwatchList(); - var spalContainer = newHTML('div', 'swatchpalette-container', div); - var spal = newHTML('div', 'swatchpalette', spalContainer); - spal.setAttribute('id', 'swatches'); - for (var i = 0; i < swatchlist.length; i++) { - var colour = newHTML('div', 'swatchbucket', spal); - // bucket - var sf = newHTML('div', 'swatchframe', colour); - var sc = newHTML('div', 'swatchcolor', sf); - sc.style.background = swatchlist[i]; - // - sf = newHTML('div', 'splasharea off', colour); - Paint.setSplashColor(sf, Paint.splash, swatchlist[i]); - Paint.addImageUrl(sf, Paint.splashshade); - colour.ontouchstart = Paint.selectSwatch; - } - Paint.setSwatchColor(gn('swatches').childNodes[swatchlist.indexOf('#1C1C1C')]); -}; - -Paint.setSplashColor = function (p, str, color) { - var dataurl = 'data:image/svg+xml;base64,' + btoa(str.replace(/#662D91/g, color)); - Paint.addImageUrl(p, dataurl); -}; - -Paint.addImageUrl = function (p, url) { - var img = document.createElement('img'); - img.src = url; - img.style.position = 'absolute'; - p.appendChild(img); -}; - -Paint.selectSwatch = function (e) { - if (e.touches && (e.touches.length > 1)) { - return; - } - e.preventDefault(); - e.stopPropagation(); - if (Camera.active) { - return; - } - var t; - if (window.event) { - t = window.event.srcElement; - } else { - t = e.target; - } - var b = 'swatchbucket' != t.className; - while (b) { - t = t.parentNode; - b = t && ('swatchbucket' != t.className); - } - if (!t) { - return; - } - ScratchAudio.sndFX('splash.wav'); - Paint.setSwatchColor(t); -}; - -Paint.setSwatchColor = function (t) { - var tools = ['select', 'wand', 'stamper', 'scissors', 'rotate']; - if (t && (tools.indexOf(Paint.mode) > -1)) { - Paint.selectButton('paintbucket'); - } - var c = t.childNodes[0].childNodes[0].style.backgroundColor; - for (var i = 0; i < gn('swatches').childElementCount; i++) { - var mycolor = gn('swatches').childNodes[i].childNodes[0].childNodes[0].style.backgroundColor; - if (c == mycolor) { - gn('swatches').childNodes[i].childNodes[1].setAttribute('class', 'splasharea on'); - } else { - gn('swatches').childNodes[i].childNodes[1].setAttribute('class', 'splasharea off'); - } - } - Paint.fillcolor = c; - Path.quitEditMode(); - Paint.updateStrokes(); -}; - -Paint.initSwatchList = function () { - return [ - // "#FF5500", // new orange - '#FFD2F2', '#FF99D6', '#FF4583', // red pinks - '#C30001', '#FF0023', '#FF8300', '#FFB200', - '#FFF42E', - '#FFF9C2', // pale yellow - '#E2FFBD', // pale green - '#CFF500', // lime green - '#50D823', // problematic - // "#2BFC49", // less problematic - '#29C130', - // "#56C43B", // ERROR? - '#2BBF8A', // new green - '#027607', '#114D24', //greens - '#FFFFFF', '#CCDDE7', '#61787C', '#1C1C1C', // grays - '#D830A3', // sarah's pink shoes border - '#FF64E9', // purple pinks - '#D999FF', ' #A159D3', // vilote - '#722696', // sarah's violet - '#141463', '#003399', '#1D40ED', - '#0079D3', '#009EFF', '#76C8FF', - '#ACE0FD', '#11B7BC', '#21F9F3', '#C3FCFC', '#54311E', - '#8E572A', '#E4B69D', '#FFCDA4', '#FFEDD7' // skin colors - - ]; -}; - -///////////////////////////////////////////////// -// Setup SVG Editor -//////////////////////////////////////////////// - - -Paint.createSVGeditor = function (container) { - var div = newHTML('div', 'maincanvas', container); - div.setAttribute('id', 'maincanvas'); - div.style.background = '#F5F2F7'; - div.style.top = '0px'; - div.style.left = '0px'; - window.onmousemove = undefined; - window.onmouseup = undefined; - Paint.root = SVGTools.create(div); - Paint.root.setAttribute('class', 'active3d'); - xform = Transform.getTranslateTransform(); - selxform = Transform.getTranslateTransform(); - var layer = SVGTools.createGroup(Paint.root, 'layer1'); - layer.setAttribute('style', 'pointer-events:visiblePainted'); - SVGTools.createGroup(Paint.root, 'draglayer'); - SVGTools.createGroup(Paint.root, 'paintgrid'); - gn('paintgrid').setAttribute('opacity', 0.5); -}; - -Paint.clearWorkspace = function () { - var fcn = function (div) { - while (div.childElementCount > 0) { - div.removeChild(div.childNodes[0]); - } - }; - fcn(gn('layer1')); - fcn(gn('paintgrid')); - fcn(gn('draglayer')); - Path.quitEditMode(); -}; - -Paint.drawGrid = function (w, h) { - var attr, path; - if (!Paint.isBkg) { - attr = { - 'd': Paint.getGridPath(w, h, 12), - 'id': getIdFor('gridpath'), - 'opacity': 1, - 'stroke': '#dcddde', - 'fill': 'none', - 'stroke-width': 0.5 - }; - path = SVGTools.addChild(gn('paintgrid'), 'path', attr); - path.setAttribute('style', 'pointer-events:none;'); - } - attr = { - 'd': Paint.getGridPath(w, h, Paint.isBkg ? 24 : 48), - 'id': getIdFor('gridpath'), - 'opacity': 1, - 'stroke': '#c1c2c3', - 'fill': 'none', - 'stroke-width': 0.5 - }; - path = SVGTools.addChild(gn('paintgrid'), 'path', attr); - path.setAttribute('style', 'pointer-events:none;'); -}; - -Paint.getGridPath = function (w, h, gridsize) { - var str = ''; - var dx = gridsize; - // vertical - var cmd; - for (var i = 0; i < w / gridsize; i++) { - cmd = 'M' + dx + ',' + 0 + 'L' + dx + ',' + h; - str += cmd; - dx += gridsize; - } - var dy = gridsize; - // horizontal - for (i = 0; i < h / gridsize; i++) { - cmd = 'M' + 0 + ',' + dy + 'L' + w + ',' + dy; - str += cmd; - dy += gridsize; - } - return str; -};