// Copyright (c) 2014-17 Walter Bender
|
|
// Copyright (c) Yash Khandelwal, GSoC'15
|
|
// Copyright (c) 2016 Tymon Radzik
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the The GNU Affero General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
|
//
|
|
// Note: This code is inspired by the Python Turtle Blocks project
|
|
// (https://github.com/walterbender/turtleart), but implemented from
|
|
// scratch. -- Walter Bender, October 2014.
|
|
|
|
const _THIS_IS_MUSIC_BLOCKS_ = false;
|
|
const _THIS_IS_TURTLE_BLOCKS_ = !_THIS_IS_MUSIC_BLOCKS_;
|
|
|
|
|
|
function facebookInit() {
|
|
window.fbAsyncInit = function () {
|
|
FB.init({
|
|
appId: '1496189893985945',
|
|
xfbml: true,
|
|
version: 'v2.1'
|
|
});
|
|
|
|
// ADD ADDITIONAL FACEBOOK CODE HERE
|
|
};
|
|
};
|
|
|
|
|
|
try {
|
|
(function (d, s, id) {
|
|
var js, fjs = d.getElementsByTagName(s)[0];
|
|
if (d.getElementById(id)) {
|
|
return;
|
|
}
|
|
|
|
js = d.createElement(s);
|
|
js.id = id;
|
|
js.src = "https://connect.facebook.net/en_US/sdk.js";
|
|
fjs.parentNode.insertBefore(js, fjs);
|
|
}(document, 'script', 'facebook-jssdk'));
|
|
} catch (e) {
|
|
};
|
|
|
|
|
|
var lang = document.webL10n.getLanguage();
|
|
if (lang.indexOf('-') !== -1) {
|
|
lang = lang.slice(0, lang.indexOf("-"));
|
|
document.webL10n.setLanguage(lang);
|
|
}
|
|
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
MYDEFINES = ["activity/sugarizer-compatibility", 'activity/platformstyle', 'easeljs-0.8.2.min', 'tweenjs-0.6.2.min', 'preloadjs-0.6.2.min', 'Tone.min', 'howler', 'p5.min', 'p5.sound.min', 'p5.dom.min', 'mespeak', 'Chart', 'activity/utils', 'activity/artwork', 'activity/status', 'activity/munsell', 'activity/trash', 'activity/boundary', 'activity/turtle', 'activity/palette', 'activity/protoblocks', 'activity/blocks', 'activity/block', 'activity/turtledefs', 'activity/logo', 'activity/clearbox', 'activity/utilitybox', 'activity/samplesviewer', 'activity/basicblocks', 'activity/blockfactory', 'activity/analytics', 'activity/modewidget', 'activity/soundsamples', 'activity/pitchtimematrix', 'activity/pitchdrummatrix', 'activity/rhythmruler', 'activity/pitchstaircase', 'activity/tempo', 'activity/pitchslider', 'activity/macros', 'activity/musicutils', 'activity/lilypond', 'prefixfree.min'];
|
|
} else {
|
|
MYDEFINES = ["activity/sugarizer-compatibility", 'activity/platformstyle', 'easeljs-0.8.2.min', 'tweenjs-0.6.2.min', 'preloadjs-0.6.2.min', 'howler', 'p5.min', 'p5.sound.min', 'p5.dom.min', 'mespeak', 'Chart', 'activity/utils', 'activity/artwork', 'activity/status', 'activity/munsell', 'activity/trash', 'activity/boundary', 'activity/turtle', 'activity/palette', 'activity/protoblocks', 'activity/blocks', 'activity/block', 'activity/turtledefs', 'activity/logo', 'activity/clearbox', 'activity/savebox', 'activity/utilitybox', 'activity/samplesviewer', 'activity/basicblocks', 'activity/blockfactory', 'activity/analytics', 'activity/macros', 'activity/musicutils', 'activity/lilypond', 'prefixfree.min'];
|
|
}
|
|
|
|
define(MYDEFINES, function (compatibility) {
|
|
|
|
// Manipulate the DOM only when it is ready.
|
|
requirejs(['domReady!','activity/sugarizer-compatibility'], function (doc) {
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
window.addEventListener('localized', function() {
|
|
sugarizerCompatibility.loadData(function () {
|
|
domReady(doc);
|
|
});
|
|
});
|
|
document.webL10n.setLanguage(sugarizerCompatibility.getLanguage());
|
|
} else {
|
|
domReady(doc);
|
|
}
|
|
});
|
|
|
|
function domReady(doc) {
|
|
createDefaultStack();
|
|
createHelpContent();
|
|
// facebookInit();
|
|
window.scroll(0, 0);
|
|
|
|
try {
|
|
meSpeak.loadConfig('lib/mespeak_config.json');
|
|
var lang = document.webL10n.getLanguage();
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
lang = sugarizerCompatibility.getLanguage();
|
|
}
|
|
if (['es', 'ca', 'de', 'el', 'eo', 'fi', 'fr', 'hu', 'it', 'kn', 'la', 'lv', 'nl', 'pl', 'pt', 'ro', 'sk', 'sv', 'tr', 'zh'].indexOf(lang) !== -1) {
|
|
meSpeak.loadVoice('lib/voices/' + lang + '.json');
|
|
} else {
|
|
meSpeak.loadVoice('lib/voices/en/en.json');
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
|
|
var canvas = docById('myCanvas');
|
|
|
|
var queue = new createjs.LoadQueue(false);
|
|
|
|
// Check for the various File API support.
|
|
if (window.File && window.FileReader && window.FileList && window.Blob) {
|
|
var files = true;
|
|
} else {
|
|
alert('The File APIs are not fully supported in this browser.');
|
|
var files = false;
|
|
}
|
|
|
|
// Set up a file chooser for the doOpen function.
|
|
var fileChooser = docById('myOpenFile');
|
|
// Set up a file chooser for the doOpenPlugin function.
|
|
var pluginChooser = docById('myOpenPlugin');
|
|
// The file chooser for all files.
|
|
var allFilesChooser = docById('myOpenAll');
|
|
|
|
// Are we running off of a server?
|
|
var server = true;
|
|
var turtleBlocksScale = 1;
|
|
var stage;
|
|
var turtles;
|
|
var palettes;
|
|
var blocks;
|
|
var logo;
|
|
var clearBox;
|
|
var utilityBox;
|
|
var thumbnails;
|
|
var buttonsVisible = true;
|
|
var headerContainer = null;
|
|
var toolbarButtonsVisible = true;
|
|
var menuButtonsVisible = true;
|
|
var menuContainer = null;
|
|
var scrollBlockContainer = false;
|
|
var currentKey = '';
|
|
var currentKeyCode = 0;
|
|
var lastKeyCode = 0;
|
|
var pasteContainer = null;
|
|
var pasteImage = null;
|
|
var chartBitmap = null;
|
|
if (_THIS_IS_TURTLE_BLOCKS_) {
|
|
var saveBox;
|
|
}
|
|
|
|
// Calculate the palette colors.
|
|
for (var p in PALETTECOLORS) {
|
|
PALETTEFILLCOLORS[p] = getMunsellColor(PALETTECOLORS[p][0], PALETTECOLORS[p][1], PALETTECOLORS[p][2]);
|
|
PALETTESTROKECOLORS[p] = getMunsellColor(PALETTECOLORS[p][0], PALETTECOLORS[p][1] - 30, PALETTECOLORS[p][2]);
|
|
PALETTEHIGHLIGHTCOLORS[p] = getMunsellColor(PALETTECOLORS[p][0], PALETTECOLORS[p][1] + 10, PALETTECOLORS[p][2]);
|
|
HIGHLIGHTSTROKECOLORS[p] = getMunsellColor(PALETTECOLORS[p][0], PALETTECOLORS[p][1] - 50, PALETTECOLORS[p][2]);
|
|
}
|
|
|
|
pluginObjs = {
|
|
'PALETTEPLUGINS': {},
|
|
'PALETTEFILLCOLORS': {},
|
|
'PALETTESTROKECOLORS': {},
|
|
'PALETTEHIGHLIGHTCOLORS': {},
|
|
'FLOWPLUGINS': {},
|
|
'ARGPLUGINS': {},
|
|
'BLOCKPLUGINS': {},
|
|
'ONLOAD': {},
|
|
'ONSTART': {},
|
|
'ONSTOP': {}
|
|
};
|
|
|
|
// Stacks of blocks saved in local storage
|
|
var macroDict = {};
|
|
|
|
var stopTurtleContainer = null;
|
|
var stopTurtleContainerX = 0;
|
|
var stopTurtleContainerY = 0;
|
|
var homeButtonContainers = [];
|
|
var homeButtonContainersX = 0;
|
|
var homeButtonContainersY = 0;
|
|
|
|
var cameraID = null;
|
|
var toLang = null;
|
|
var fromLang = null;
|
|
|
|
// initial scroll position
|
|
var scrollX = 0;
|
|
var scrollY = 0;
|
|
|
|
// default values
|
|
const DEFAULTDELAY = 500; // milleseconds
|
|
const TURTLESTEP = -1; // Run in step-by-step mode
|
|
|
|
const BLOCKSCALES = [1, 1.5, 2, 3, 4];
|
|
var blockscale = BLOCKSCALES.indexOf(DEFAULTBLOCKSCALE);
|
|
if (blockscale === -1) {
|
|
blockscale = 1;
|
|
}
|
|
|
|
// Time when we hit run
|
|
var time = 0;
|
|
|
|
// Used by pause block
|
|
var waitTime = {};
|
|
|
|
// Used to track mouse state for mouse button block
|
|
var stageMouseDown = false;
|
|
var stageX = 0;
|
|
var stageY = 0;
|
|
|
|
var onXO = (screen.width === 1200 && screen.height === 900) || (screen.width === 900 && screen.height === 1200);
|
|
|
|
var cellSize = 55;
|
|
if (onXO) {
|
|
cellSize = 75;
|
|
}
|
|
|
|
var onscreenButtons = [];
|
|
var onscreenMenu = [];
|
|
var utilityButton = null;
|
|
var saveButton = null;
|
|
|
|
var helpContainer = null;
|
|
var helpIdx = 0;
|
|
var firstRun = true;
|
|
|
|
pluginsImages = {};
|
|
|
|
// Sometimes (race condition?) Firefox does not properly
|
|
// initialize strings in musicutils. These methods ensure that
|
|
// the names are never null.
|
|
console.log('initing i18n for music terms');
|
|
initDrumI18N();
|
|
initModeI18N();
|
|
initVoiceI18N();
|
|
|
|
window.onblur = function () {
|
|
logo.doStopTurtle();
|
|
};
|
|
|
|
function _findBlocks() {
|
|
logo.showBlocks();
|
|
blocksContainer.x = 0;
|
|
blocksContainer.y = 0;
|
|
palettes.initial_x = 55;
|
|
palettes.initial_y = 55;
|
|
palettes.updatePalettes();
|
|
var x = 100 * turtleBlocksScale;
|
|
var y = 100 * turtleBlocksScale;
|
|
for (var blk in blocks.blockList) {
|
|
if (!blocks.blockList[blk].trash) {
|
|
var myBlock = blocks.blockList[blk];
|
|
if (myBlock.connections[0] == null) {
|
|
var dx = x - myBlock.container.x;
|
|
var dy = y - myBlock.container.y;
|
|
blocks.moveBlockRelative(blk, dx, dy);
|
|
blocks.findDragGroup(blk);
|
|
if (blocks.dragGroup.length > 0) {
|
|
for (var b = 0; b < blocks.dragGroup.length; b++) {
|
|
var bblk = blocks.dragGroup[b];
|
|
if (b !== 0) {
|
|
blocks.moveBlockRelative(bblk, dx, dy);
|
|
}
|
|
}
|
|
}
|
|
x += 200 * turtleBlocksScale;
|
|
if (x > (canvas.width - 100) / (turtleBlocksScale)) {
|
|
x = 100 * turtleBlocksScale;
|
|
y += 100 * turtleBlocksScale;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Blocks are all home, so reset go-home-button.
|
|
homeButtonContainers[0].visible = false;
|
|
homeButtonContainers[1].visible = true;
|
|
boundary.hide();
|
|
};
|
|
|
|
function _allClear() {
|
|
if (chartBitmap != null) {
|
|
stage.removeChild(chartBitmap);
|
|
chartBitmap = null;
|
|
}
|
|
|
|
logo.boxes = {};
|
|
logo.time = 0;
|
|
hideMsgs();
|
|
logo.setBackgroundColor(-1);
|
|
logo.lilypondOutput = LILYPONDHEADER;
|
|
for (var turtle = 0; turtle < turtles.turtleList.length; turtle++) {
|
|
logo.turtleHeaps[turtle] = [];
|
|
logo.lilypondStaging[turtle] = [];
|
|
turtles.turtleList[turtle].doClear(true, true);
|
|
}
|
|
|
|
blocksContainer.x = 0;
|
|
blocksContainer.y = 0;
|
|
|
|
// Code specific to cleaning up music blocks
|
|
Element.prototype.remove = function () {
|
|
this.parentElement.removeChild(this);
|
|
};
|
|
|
|
NodeList.prototype.remove = HTMLCollection.prototype.remove = function () {
|
|
for (var i = 0, len = this.length; i < len; i++) {
|
|
if(this[i] && this[i].parentElement) {
|
|
this[i].parentElement.removeChild(this[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
var table = document.getElementById("myTable");
|
|
if(table != null) {
|
|
table.remove();
|
|
}
|
|
|
|
/*
|
|
var canvas = document.getElementById("music");
|
|
var context = canvas.getContext("2d");
|
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
*/
|
|
};
|
|
|
|
function _doFastButton(env) {
|
|
var currentDelay = logo.turtleDelay;
|
|
var playingWidget = false;
|
|
logo.setTurtleDelay(0);
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
if (docById('ptmDiv').style.visibility === 'visible') {
|
|
playingWidget = true;
|
|
logo.pitchTimeMatrix.playAll();
|
|
}
|
|
|
|
if (docById('pscDiv').style.visibility === 'visible') {
|
|
playingWidget = true;
|
|
pitchstaircase.playUpAndDown();
|
|
}
|
|
|
|
if (docById('rulerDiv').style.visibility === 'visible') {
|
|
// If the tempo widget is open, sync it up with the
|
|
// rhythm ruler.
|
|
if (docById('tempoDiv').style.visibility === 'visible') {
|
|
if (tempo.isMoving) {
|
|
tempo.pause();
|
|
}
|
|
tempo.resume();
|
|
}
|
|
|
|
playingWidget = true;
|
|
rhythmruler.playAll();
|
|
}
|
|
|
|
// We were using the run button to play a widget, not
|
|
// the turtles.
|
|
if (playingWidget) {
|
|
return;
|
|
}
|
|
|
|
// Restart tempo widget and run blocks.
|
|
if (docById('tempoDiv').style.visibility === 'visible') {
|
|
if (tempo.isMoving) {
|
|
tempo.pause();
|
|
}
|
|
|
|
tempo.resume();
|
|
}
|
|
}
|
|
|
|
if (!turtles.running()) {
|
|
console.log('running');
|
|
logo.runLogoCommands(null, env);
|
|
} else {
|
|
if (currentDelay !== 0) {
|
|
// keep playing at full speep
|
|
console.log('running from step');
|
|
logo.step();
|
|
} else {
|
|
// stop and restart
|
|
console.log('stopping...');
|
|
logo.doStopTurtle();
|
|
|
|
setTimeout(function () {
|
|
console.log('and running');
|
|
logo.runLogoCommands(null, env);
|
|
}, 500);
|
|
}
|
|
}
|
|
};
|
|
|
|
function _doSlowButton() {
|
|
logo.setTurtleDelay(DEFAULTDELAY);
|
|
if (_THIS_IS_MUSIC_BLOCKS_ && docById('ptmDiv').style.visibility === 'visible') {
|
|
logo.pitchTimeMatrix.playAll();
|
|
} else if (!turtles.running()) {
|
|
logo.runLogoCommands();
|
|
} else {
|
|
logo.step();
|
|
}
|
|
};
|
|
|
|
function _doStepButton() {
|
|
var turtleCount = 0;
|
|
for (var turtle in logo.stepQueue) {
|
|
turtleCount += 1;
|
|
}
|
|
|
|
if (turtleCount === 0 || logo.turtleDelay !== TURTLESTEP) {
|
|
// Either we haven't set up a queue or we are
|
|
// switching modes.
|
|
logo.setTurtleDelay(TURTLESTEP);
|
|
// Queue and take first step.
|
|
if (!turtles.running()) {
|
|
logo.runLogoCommands();
|
|
}
|
|
logo.step();
|
|
} else {
|
|
logo.setTurtleDelay(TURTLESTEP);
|
|
logo.step();
|
|
}
|
|
};
|
|
|
|
function _doSlowMusicButton() {
|
|
logo.setNoteDelay(DEFAULTDELAY);
|
|
|
|
if (docById('ptmDiv').style.visibility === 'visible') {
|
|
logo.pitchTimeMatrix.playAll();
|
|
} else if (!turtles.running()) {
|
|
logo.runLogoCommands();
|
|
} else {
|
|
logo.stepNote();
|
|
}
|
|
};
|
|
|
|
function _doStepMusicButton() {
|
|
var turtleCount = 0;
|
|
for (var turtle in logo.stepQueue) {
|
|
turtleCount += 1;
|
|
}
|
|
|
|
if (turtleCount === 0 || logo.TurtleDelay !== TURTLESTEP) {
|
|
// Either we haven't set up a queue or we are
|
|
// switching modes.
|
|
logo.setTurtleDelay(TURTLESTEP);
|
|
// Queue and take first step.
|
|
if (!turtles.running()) {
|
|
logo.runLogoCommands();
|
|
}
|
|
logo.stepNote();
|
|
} else {
|
|
logo.setTurtleDelay(TURTLESTEP);
|
|
logo.stepNote();
|
|
}
|
|
};
|
|
|
|
var stopTurtle = false;
|
|
|
|
function doStopButton() {
|
|
logo.doStopTurtle();
|
|
};
|
|
|
|
var cartesianVisible = false;
|
|
|
|
function _doCartesian() {
|
|
if (cartesianVisible) {
|
|
_hideCartesian();
|
|
cartesianVisible = false;
|
|
} else {
|
|
_showCartesian();
|
|
cartesianVisible = true;
|
|
}
|
|
};
|
|
|
|
var polarVisible = false;
|
|
|
|
function _doPolar() {
|
|
if (polarVisible) {
|
|
_hidePolar();
|
|
polarVisible = false;
|
|
} else {
|
|
_showPolar();
|
|
polarVisible = true;
|
|
}
|
|
};
|
|
|
|
function toggleScroller() {
|
|
scrollBlockContainer = !scrollBlockContainer;
|
|
};
|
|
|
|
function closeAnalytics(chartBitmap, ctx) {
|
|
var button = this;
|
|
button.x = (canvas.width / (2 * turtleBlocksScale)) + (300 / Math.sqrt(2));
|
|
button.y = 300.00 - (300.00 / Math.sqrt(2));
|
|
this.closeButton = _makeButton('cancel-button', _('Close'), button.x, button.y, 55, 0);
|
|
this.closeButton.on('click', function (event) {
|
|
console.log('Deleting Chart');
|
|
button.closeButton.visible = false;
|
|
stage.removeChild(chartBitmap);
|
|
logo.showBlocks();
|
|
update = true;
|
|
ctx.clearRect(0, 0, 600, 600);
|
|
});
|
|
};
|
|
|
|
function _isCanvasBlank(canvas) {
|
|
var blank = document.createElement('canvas');
|
|
blank.width = canvas.width;
|
|
blank.height = canvas.height;
|
|
return canvas.toDataURL() == blank.toDataURL();
|
|
};
|
|
|
|
function doAnalytics() {
|
|
var myChart = docById('myChart');
|
|
|
|
if(_isCanvasBlank(myChart) == false) {
|
|
return ;
|
|
}
|
|
|
|
var ctx = myChart.getContext('2d');
|
|
document.body.style.cursor = 'wait';
|
|
var myRadarChart = null;
|
|
var scores = analyzeProject(blocks);
|
|
console.log(scores);
|
|
var data = scoreToChartData(scores);
|
|
var Analytics = this;
|
|
Analytics.close = closeAnalytics;
|
|
|
|
var __callback = function () {
|
|
var imageData = myRadarChart.toBase64Image();
|
|
var img = new Image();
|
|
img.onload = function () {
|
|
var chartBitmap = new createjs.Bitmap(img);
|
|
stage.addChild(chartBitmap);
|
|
chartBitmap.x = (canvas.width / (2 * turtleBlocksScale)) - (300);
|
|
chartBitmap.y = 0;
|
|
chartBitmap.scaleX = chartBitmap.scaleY = chartBitmap.scale = 600 / chartBitmap.image.width;
|
|
logo.hideBlocks();
|
|
update = true;
|
|
document.body.style.cursor = 'default';
|
|
Analytics.close(chartBitmap, ctx);
|
|
};
|
|
img.src = imageData;
|
|
};
|
|
|
|
var options = getChartOptions(__callback);
|
|
console.log('creating new chart');
|
|
myRadarChart = new Chart(ctx).Radar(data, options);
|
|
};
|
|
|
|
function doBiggerFont() {
|
|
if (blockscale < BLOCKSCALES.length - 1) {
|
|
blockscale += 1;
|
|
blocks.setBlockScale(BLOCKSCALES[blockscale]);
|
|
}
|
|
};
|
|
|
|
function doSmallerFont() {
|
|
if (blockscale > 0) {
|
|
blockscale -= 1;
|
|
blocks.setBlockScale(BLOCKSCALES[blockscale]);
|
|
}
|
|
};
|
|
|
|
// Do we need to update the stage?
|
|
var update = true;
|
|
|
|
// The dictionary of action name: block
|
|
var actions = {};
|
|
|
|
// The dictionary of box name: value
|
|
var boxes = {};
|
|
|
|
// Coordinate grid
|
|
var cartesianBitmap = null;
|
|
|
|
// Polar grid
|
|
var polarBitmap = null;
|
|
|
|
// Msg block
|
|
var msgText = null;
|
|
|
|
// ErrorMsg block
|
|
var errorMsgText = null;
|
|
var errorMsgArrow = null;
|
|
var errorArtwork = {};
|
|
const ERRORARTWORK = ['emptybox', 'emptyheap', 'negroot', 'noinput', 'zerodivide', 'notanumber', 'nostack', 'notastring', 'nomicrophone'];
|
|
|
|
// Get things started
|
|
init();
|
|
|
|
function init() {
|
|
docById('loader').className = 'loader';
|
|
|
|
stage = new createjs.Stage(canvas);
|
|
createjs.Touch.enable(stage);
|
|
|
|
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED;
|
|
createjs.Ticker.setFPS(30);
|
|
createjs.Ticker.addEventListener('tick', stage);
|
|
createjs.Ticker.addEventListener('tick', __tick);
|
|
|
|
_createMsgContainer('#ffffff', '#7a7a7a', function (text) {
|
|
msgText = text;
|
|
}, 55);
|
|
|
|
_createMsgContainer('#ffcbc4', '#ff0031', function (text) {
|
|
errorMsgText = text;
|
|
}, 110);
|
|
|
|
_createErrorContainers();
|
|
|
|
/* Z-Order (top to bottom):
|
|
* menus
|
|
* palettes
|
|
* blocks
|
|
* trash
|
|
* turtles
|
|
* logo (drawing)
|
|
*/
|
|
palettesContainer = new createjs.Container();
|
|
blocksContainer = new createjs.Container();
|
|
trashContainer = new createjs.Container();
|
|
turtleContainer = new createjs.Container();
|
|
|
|
stage.addChild(turtleContainer, trashContainer, blocksContainer, palettesContainer);
|
|
_setupBlocksContainerEvents();
|
|
|
|
trashcan = new Trashcan();
|
|
trashcan
|
|
.setCanvas(canvas)
|
|
.setStage(trashContainer)
|
|
.setSize(cellSize)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.init();
|
|
|
|
turtles = new Turtles();
|
|
turtles
|
|
.setCanvas(canvas)
|
|
.setStage(turtleContainer)
|
|
.setRefreshCanvas(refreshCanvas);
|
|
|
|
// Put the boundary in the blocks container so it scrolls
|
|
// with the blocks.
|
|
boundary = new Boundary();
|
|
boundary
|
|
.setStage(blocksContainer)
|
|
.init();
|
|
|
|
blocks = new Blocks();
|
|
blocks
|
|
.setCanvas(canvas)
|
|
.setStage(blocksContainer)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setTrashcan(trashcan)
|
|
.setUpdateStage(stage.update)
|
|
.setGetStageScale(getStageScale)
|
|
.setTurtles(turtles)
|
|
.setErrorMsg(errorMsg);
|
|
blocks.makeCopyPasteButtons(_makeButton, updatePasteButton);
|
|
|
|
turtles.setBlocks(blocks);
|
|
|
|
palettes = new Palettes();
|
|
palettes
|
|
.setCanvas(canvas)
|
|
.setStage(palettesContainer)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setSize(cellSize)
|
|
.setTrashcan(trashcan)
|
|
.setBlocks(blocks)
|
|
.init();
|
|
|
|
initPalettes(palettes);
|
|
|
|
logo = new Logo();
|
|
logo
|
|
.setCanvas(canvas)
|
|
.setBlocks(blocks)
|
|
.setTurtles(turtles)
|
|
.setStage(turtleContainer)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setTextMsg(textMsg)
|
|
.setErrorMsg(errorMsg)
|
|
.setHideMsgs(hideMsgs)
|
|
.setOnStopTurtle(onStopTurtle)
|
|
.setOnRunTurtle(onRunTurtle)
|
|
.setGetStageX(getStageX)
|
|
.setGetStageY(getStageY)
|
|
.setGetStageMouseDown(getStageMouseDown)
|
|
.setGetCurrentKeyCode(getCurrentKeyCode)
|
|
.setClearCurrentKeyCode(clearCurrentKeyCode)
|
|
.setMeSpeak(meSpeak)
|
|
.setSaveLocally(saveLocally);
|
|
|
|
blocks.setLogo(logo);
|
|
|
|
// Set the default background color...
|
|
logo.setBackgroundColor(-1);
|
|
|
|
clearBox = new ClearBox();
|
|
clearBox
|
|
.setCanvas(canvas)
|
|
.setStage(stage)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setClear(sendAllToTrash);
|
|
|
|
if (_THIS_IS_TURTLE_BLOCKS_) {
|
|
saveBox = new SaveBox();
|
|
saveBox
|
|
.setCanvas(canvas)
|
|
.setStage(stage)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setSaveTB(doSaveTB)
|
|
.setSaveSVG(doSaveSVG)
|
|
.setSavePNG(doSavePNG)
|
|
.setSavePlanet(doUploadToPlanet)
|
|
.setSaveFB(doShareOnFacebook);
|
|
}
|
|
|
|
utilityBox = new UtilityBox();
|
|
utilityBox
|
|
.setStage(stage)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setBigger(doBiggerFont)
|
|
.setSmaller(doSmallerFont)
|
|
.setPlugins(doOpenPlugin)
|
|
.setStats(doAnalytics)
|
|
.setScroller(toggleScroller);
|
|
|
|
thumbnails = new SamplesViewer();
|
|
thumbnails
|
|
.setStage(stage)
|
|
.setRefreshCanvas(refreshCanvas)
|
|
.setClear(sendAllToTrash)
|
|
.setLoad(loadProject)
|
|
.setLoadRaw(loadRawProject)
|
|
.init();
|
|
|
|
initBasicProtoBlocks(palettes, blocks);
|
|
|
|
// Load any macros saved in local storage.
|
|
macroData = storage.macros;
|
|
if (macroData != null) {
|
|
processMacroData(macroData, palettes, blocks, macroDict);
|
|
}
|
|
|
|
// Blocks and palettes need access to the macros dictionary.
|
|
blocks.setMacroDictionary(macroDict);
|
|
palettes.setMacroDictionary(macroDict);
|
|
|
|
// Load any plugins saved in local storage.
|
|
pluginData = storage.plugins;
|
|
if (pluginData != null) {
|
|
var obj = processPluginData(pluginData, palettes, blocks, logo.evalFlowDict, logo.evalArgDict, logo.evalParameterDict, logo.evalSetterDict, logo.evalOnStartList, logo.evalOnStopList);
|
|
updatePluginObj(obj);
|
|
}
|
|
|
|
// Load custom mode saved in local storage.
|
|
var custommodeData = storage.custommode;
|
|
if (custommodeData != undefined) {
|
|
customMode = JSON.parse(custommodeData);
|
|
console.log('restoring custom mode: ' + customMode);
|
|
}
|
|
|
|
fileChooser.addEventListener('click', function (event) {
|
|
this.value = null;
|
|
});
|
|
|
|
fileChooser.addEventListener('change', function (event) {
|
|
// Read file here.
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = (function (theFile) {
|
|
// Show busy cursor.
|
|
document.body.style.cursor = 'wait';
|
|
setTimeout(function () {
|
|
var rawData = reader.result;
|
|
var cleanData = rawData.replace('\n', ' ');
|
|
var obj = JSON.parse(cleanData);
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
|
|
refreshCanvas();
|
|
|
|
blocks.loadNewBlocks(obj);
|
|
// Restore default cursor.
|
|
document.body.style.cursor = 'default';
|
|
}, 200);
|
|
});
|
|
|
|
reader.readAsText(fileChooser.files[0]);
|
|
}, false);
|
|
|
|
allFilesChooser.addEventListener('click', function (event) {
|
|
this.value = null;
|
|
});
|
|
|
|
pluginChooser.addEventListener('click', function (event) {
|
|
window.scroll(0, 0);
|
|
this.value = null;
|
|
});
|
|
|
|
pluginChooser.addEventListener('change', function (event) {
|
|
window.scroll(0, 0);
|
|
|
|
// Read file here.
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = (function (theFile) {
|
|
// Show busy cursor.
|
|
document.body.style.cursor = 'wait';
|
|
setTimeout(function () {
|
|
obj = processRawPluginData(reader.result, palettes, blocks, errorMsg, logo.evalFlowDict, logo.evalArgDict, logo.evalParameterDict, logo.evalSetterDict, logo.evalOnStartList, logo.evalOnStopList);
|
|
// Save plugins to local storage.
|
|
if (obj != null) {
|
|
var pluginObj = preparePluginExports(obj);
|
|
console.log(pluginObj);
|
|
storage.plugins = pluginObj; // preparePluginExports(obj));
|
|
}
|
|
|
|
// Refresh the palettes.
|
|
setTimeout(function () {
|
|
if (palettes.visible) {
|
|
palettes.hide();
|
|
}
|
|
palettes.show();
|
|
palettes.bringToTop();
|
|
}, 1000);
|
|
|
|
// Restore default cursor.
|
|
document.body.style.cursor = 'default';
|
|
}, 200);
|
|
});
|
|
|
|
reader.readAsText(pluginChooser.files[0]);
|
|
}, false);
|
|
|
|
// Workaround to chrome security issues
|
|
// createjs.LoadQueue(true, null, true);
|
|
|
|
// Enable touch interactions if supported on the current device.
|
|
// FIXME: voodoo
|
|
// createjs.Touch.enable(stage, false, true);
|
|
// Keep tracking the mouse even when it leaves the canvas.
|
|
stage.mouseMoveOutside = true;
|
|
// Enabled mouse over and mouse out events.
|
|
stage.enableMouseOver(10); // default is 20
|
|
|
|
cartesianBitmap = _createGrid('images/Cartesian.svg');
|
|
|
|
polarBitmap = _createGrid('images/polar.svg');
|
|
|
|
var URL = window.location.href;
|
|
var projectName = null;
|
|
var runProjectOnLoad = false;
|
|
|
|
_setupAndroidToolbar();
|
|
|
|
// Scale the canvas relative to the screen size.
|
|
_onResize();
|
|
|
|
var urlParts;
|
|
var env = [];
|
|
|
|
if (!sugarizerCompatibility.isInsideSugarizer() && URL.indexOf('?') > 0) {
|
|
var urlParts = URL.split('?');
|
|
if (urlParts[1].indexOf('&') > 0) {
|
|
var newUrlParts = urlParts[1].split('&');
|
|
for (var i = 0; i < newUrlParts.length; i++) {
|
|
if (newUrlParts[i].indexOf('=') > 0) {
|
|
var args = newUrlParts[i].split('=');
|
|
switch (args[0].toLowerCase()) {
|
|
case 'file':
|
|
projectName = args[1];
|
|
break;
|
|
case 'run':
|
|
if (args[1].toLowerCase() === 'true')
|
|
runProjectOnLoad = true;
|
|
break;
|
|
case 'inurl':
|
|
var url = args[1];
|
|
var getJSON = function (url) {
|
|
return new Promise(function (resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('get', url, true);
|
|
xhr.responseType = 'json';
|
|
xhr.onload = function () {
|
|
var status = xhr.status;
|
|
if (status === 200) {
|
|
resolve(xhr.response);
|
|
} else {
|
|
reject(status);
|
|
}
|
|
};
|
|
xhr.send();
|
|
});
|
|
};
|
|
getJSON(url).then(function (data) {
|
|
console.log('Your Json result is: ' + data.arg); //you can comment this, i used it to debug
|
|
n = data.arg;
|
|
env.push(parseInt(n));
|
|
}, function (status) { //error detection....
|
|
alert('Something went wrong.');
|
|
});
|
|
break;
|
|
case 'outurl':
|
|
var url = args[1];
|
|
break;
|
|
default:
|
|
errorMsg("Invalid parameters");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (urlParts[1].indexOf('=') > 0)
|
|
var args = urlParts[1].split('=');
|
|
//File is the only arg that can stand alone
|
|
if (args[0].toLowerCase() === 'file') {
|
|
projectName = args[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (projectName != null) {
|
|
setTimeout(function () {
|
|
console.log('loading ' + projectName);
|
|
loadStartWrapper(loadProject, projectName, runProjectOnLoad, env);
|
|
}, 2000);
|
|
} else {
|
|
setTimeout(function () {
|
|
loadStartWrapper(_loadStart);
|
|
}, 2000);
|
|
}
|
|
|
|
document.addEventListener('mousewheel', scrollEvent, false);
|
|
document.addEventListener('DOMMouseScroll', scrollEvent, false);
|
|
|
|
this.document.onkeydown = __keyPressed;
|
|
_hideStopButton();
|
|
|
|
};
|
|
|
|
function _setupBlocksContainerEvents() {
|
|
var moving = false;
|
|
|
|
stage.on('stagemousemove', function (event) {
|
|
stageX = event.stageX;
|
|
stageY = event.stageY;
|
|
});
|
|
|
|
stage.on('stagemousedown', function (event) {
|
|
stageMouseDown = true;
|
|
if (stage.getObjectUnderPoint() != null | turtles.running()) {
|
|
stage.on('stagemouseup', function (event) {
|
|
stageMouseDown = false;
|
|
});
|
|
return;
|
|
}
|
|
moving = true;
|
|
lastCords = {
|
|
x: event.stageX,
|
|
y: event.stageY
|
|
};
|
|
|
|
stage.on('stagemousemove', function (event) {
|
|
if (!moving) {
|
|
return;
|
|
}
|
|
if (blocks.inLongPress) {
|
|
blocks.saveStackButton.visible = false;
|
|
blocks.dismissButton.visible = false;
|
|
blocks.inLongPress = false;
|
|
}
|
|
if (scrollBlockContainer) {
|
|
blocksContainer.x += event.stageX - lastCords.x;
|
|
blocksContainer.y += event.stageY - lastCords.y;
|
|
lastCords = {
|
|
x: event.stageX,
|
|
y: event.stageY
|
|
};
|
|
refreshCanvas();
|
|
}
|
|
});
|
|
|
|
stage.on('stagemouseup', function (event) {
|
|
stageMouseDown = false;
|
|
moving = false;
|
|
}, null, true); // once = true
|
|
});
|
|
};
|
|
|
|
function scrollEvent(event) {
|
|
var data = event.wheelDelta || -event.detail;
|
|
var delta = Math.max(-1, Math.min(1, (data)));
|
|
var scrollSpeed = 30;
|
|
|
|
if (event.clientX < cellSize) {
|
|
palettes.menuScrollEvent(delta, scrollSpeed);
|
|
palettes.hidePaletteIconCircles();
|
|
} else {
|
|
palette = palettes.findPalette(event.clientX / turtleBlocksScale, event.clientY / turtleBlocksScale);
|
|
if (palette) {
|
|
palette.scrollEvent(delta, scrollSpeed);
|
|
}
|
|
}
|
|
};
|
|
|
|
function getStageScale() {
|
|
return turtleBlocksScale;
|
|
};
|
|
|
|
function getStageX() {
|
|
return turtles.screenX2turtleX(stageX / turtleBlocksScale);
|
|
};
|
|
|
|
function getStageY() {
|
|
return turtles.screenY2turtleY(stageY / turtleBlocksScale);
|
|
};
|
|
|
|
function getStageMouseDown() {
|
|
return stageMouseDown;
|
|
};
|
|
|
|
function setCameraID(id) {
|
|
cameraID = id;
|
|
};
|
|
|
|
function _createGrid(imagePath) {
|
|
var img = new Image();
|
|
img.src = imagePath;
|
|
var container = new createjs.Container();
|
|
stage.addChild(container);
|
|
|
|
var bitmap = new createjs.Bitmap(img);
|
|
container.addChild(bitmap);
|
|
bitmap.cache(0, 0, 1200, 900);
|
|
|
|
bitmap.x = (canvas.width - 1200) / 2;
|
|
bitmap.y = (canvas.height - 900) / 2;
|
|
bitmap.scaleX = bitmap.scaleY = bitmap.scale = 1;
|
|
bitmap.visible = false;
|
|
bitmap.updateCache();
|
|
|
|
return bitmap;
|
|
};
|
|
|
|
function _createMsgContainer(fillColor, strokeColor, callback, y) {
|
|
var container = new createjs.Container();
|
|
stage.addChild(container);
|
|
container.x = (canvas.width - 1000) / 2;
|
|
container.y = y;
|
|
container.visible = false;
|
|
|
|
var img = new Image();
|
|
var svgData = MSGBLOCK.replace('fill_color', fillColor).replace(
|
|
'stroke_color', strokeColor);
|
|
|
|
img.onload = function () {
|
|
var msgBlock = new createjs.Bitmap(img);
|
|
container.addChild(msgBlock);
|
|
var text = new createjs.Text('your message here', '20px Arial', '#000000');
|
|
container.addChild(text);
|
|
text.textAlign = 'center';
|
|
text.textBaseline = 'alphabetic';
|
|
text.x = 500;
|
|
text.y = 30;
|
|
|
|
var bounds = container.getBounds();
|
|
container.cache(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
|
|
var hitArea = new createjs.Shape();
|
|
hitArea.graphics.beginFill('#FFF').drawRect(0, 0, 1000, 42);
|
|
hitArea.x = 0;
|
|
hitArea.y = 0;
|
|
container.hitArea = hitArea;
|
|
|
|
container.on('click', function (event) {
|
|
container.visible = false;
|
|
// On the possibility that there was an error
|
|
// arrow associated with this container
|
|
if (errorMsgArrow != null) {
|
|
errorMsgArrow.removeAllChildren(); // Hide the error arrow.
|
|
}
|
|
update = true;
|
|
});
|
|
callback(text);
|
|
blocks.setMsgText(text);
|
|
};
|
|
|
|
img.src = 'data:image/svg+xml;base64,' + window.btoa(
|
|
unescape(encodeURIComponent(svgData)));
|
|
};
|
|
|
|
function _createErrorContainers() {
|
|
// Some error messages have special artwork.
|
|
for (var i = 0; i < ERRORARTWORK.length; i++) {
|
|
var name = ERRORARTWORK[i];
|
|
_makeErrorArtwork(name);
|
|
}
|
|
};
|
|
|
|
function _makeErrorArtwork(name) {
|
|
var container = new createjs.Container();
|
|
stage.addChild(container);
|
|
container.x = (canvas.width - 1000) / 2;
|
|
container.y = 110;
|
|
errorArtwork[name] = container;
|
|
errorArtwork[name].name = name;
|
|
errorArtwork[name].visible = false;
|
|
|
|
var img = new Image();
|
|
img.onload = function () {
|
|
// console.log('creating error message artwork for ' + img.src);
|
|
var artwork = new createjs.Bitmap(img);
|
|
container.addChild(artwork);
|
|
var text = new createjs.Text('', '20px Sans', '#000000');
|
|
container.addChild(text);
|
|
text.x = 70;
|
|
text.y = 10;
|
|
|
|
var bounds = container.getBounds();
|
|
container.cache(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
|
|
var hitArea = new createjs.Shape();
|
|
hitArea.graphics.beginFill('#FFF').drawRect(0, 0, bounds.width, bounds.height);
|
|
hitArea.x = 0;
|
|
hitArea.y = 0;
|
|
container.hitArea = hitArea;
|
|
|
|
container.on('click', function (event) {
|
|
container.visible = false;
|
|
// On the possibility that there was an error
|
|
// arrow associated with this container
|
|
if (errorMsgArrow != null) {
|
|
errorMsgArrow.removeAllChildren(); // Hide the error arrow.
|
|
}
|
|
update = true;
|
|
});
|
|
};
|
|
|
|
img.src = 'images/' + name + '.svg';
|
|
};
|
|
|
|
function __keyPressed(event) {
|
|
if (docById('labelDiv').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
if (docById('BPMInput').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
|
|
if (docById('musicratio1').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
|
|
if (docById('musicratio2').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
|
|
if (docById('dissectNumber').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const BACKSPACE = 8;
|
|
const TAB = 9;
|
|
if (event.keyCode === TAB || event.keyCode === BACKSPACE) {
|
|
// Prevent browser from grabbing TAB key
|
|
event.preventDefault();
|
|
}
|
|
|
|
const ESC = 27;
|
|
const ALT = 18;
|
|
const CTRL = 17;
|
|
const SHIFT = 16;
|
|
const RETURN = 13;
|
|
const SPACE = 32;
|
|
const HOME = 36;
|
|
const PAGE_UP = 33;
|
|
const PAGE_DOWN = 34;
|
|
const KEYCODE_LEFT = 37;
|
|
const KEYCODE_RIGHT = 39;
|
|
const KEYCODE_UP = 38;
|
|
const KEYCODE_DOWN = 40;
|
|
|
|
if (event.altKey) {
|
|
switch (event.keyCode) {
|
|
case 69: // 'E'
|
|
_allClear();
|
|
break;
|
|
case 82: // 'R'
|
|
_doFastButton();
|
|
break;
|
|
case 83: // 'S'
|
|
logo.doStopTurtle();
|
|
break;
|
|
}
|
|
} else if (event.ctrlKey) {
|
|
} else {
|
|
switch (event.keyCode) {
|
|
case KEYCODE_UP:
|
|
if (blocks.activeBlock != null) {
|
|
blocks.moveStackRelative(blocks.activeBlock, 0, -STANDARDBLOCKHEIGHT / 2);
|
|
blocks.blockMoved(blocks.activeBlock);
|
|
blocks.adjustDocks(blocks.activeBlock, true);
|
|
} else if (palettes.mouseOver) {
|
|
palettes.menuScrollEvent(1, 10);
|
|
palettes.hidePaletteIconCircles();
|
|
} else if (palettes.activePalette != null) {
|
|
palettes.activePalette.scrollEvent(STANDARDBLOCKHEIGHT, 1);
|
|
} else if (scrollBlockContainer) {
|
|
blocksContainer.y -= 21;
|
|
}
|
|
break;
|
|
case KEYCODE_DOWN:
|
|
if (blocks.activeBlock != null) {
|
|
blocks.moveStackRelative(blocks.activeBlock, 0, STANDARDBLOCKHEIGHT / 2);
|
|
blocks.blockMoved(blocks.activeBlock);
|
|
blocks.adjustDocks(blocks.activeBlock, true);
|
|
} else if (palettes.mouseOver) {
|
|
palettes.menuScrollEvent(-1, 10);
|
|
palettes.hidePaletteIconCircles();
|
|
} else if (palettes.activePalette != null) {
|
|
palettes.activePalette.scrollEvent(-STANDARDBLOCKHEIGHT, 1);
|
|
} else if (scrollBlockContainer) {
|
|
blocksContainer.y += 21;
|
|
}
|
|
break;
|
|
case KEYCODE_LEFT:
|
|
if (blocks.activeBlock != null) {
|
|
blocks.moveStackRelative(blocks.activeBlock, -STANDARDBLOCKHEIGHT / 2, 0);
|
|
blocks.blockMoved(blocks.activeBlock);
|
|
blocks.adjustDocks(blocks.activeBlock, true);
|
|
} else if (scrollBlockContainer) {
|
|
blocksContainer.x -= 21;
|
|
}
|
|
break;
|
|
case KEYCODE_RIGHT:
|
|
if (blocks.activeBlock != null) {
|
|
blocks.moveStackRelative(blocks.activeBlock, STANDARDBLOCKHEIGHT / 2, 0);
|
|
blocks.blockMoved(blocks.activeBlock);
|
|
blocks.adjustDocks(blocks.activeBlock, true);
|
|
} else if (scrollBlockContainer) {
|
|
blocksContainer.x += 21;
|
|
}
|
|
break;
|
|
case HOME:
|
|
if (palettes.mouseOver) {
|
|
var dy = Math.max(55 - palettes.buttons['rhythm'].y, 0);
|
|
palettes.menuScrollEvent(1, dy);
|
|
palettes.hidePaletteIconCircles();
|
|
} else if (palettes.activePalette != null) {
|
|
palettes.activePalette.scrollEvent(-palettes.activePalette.scrollDiff, 1);
|
|
} else {
|
|
_findBlocks();
|
|
}
|
|
break;
|
|
case TAB:
|
|
break;
|
|
case ESC:
|
|
// toggle full screen
|
|
_toggleToolbar();
|
|
break;
|
|
case RETURN:
|
|
// toggle run
|
|
logo.runLogoCommands();
|
|
break;
|
|
default:
|
|
// currentKey = String.fromCharCode(event.keyCode);
|
|
// currentKeyCode = event.keyCode;
|
|
break;
|
|
}
|
|
// Always store current key so as not to mask it from
|
|
// the keyboard block.
|
|
currentKey = String.fromCharCode(event.keyCode);
|
|
currentKeyCode = event.keyCode;
|
|
}
|
|
};
|
|
|
|
function getCurrentKeyCode() {
|
|
return currentKeyCode;
|
|
};
|
|
|
|
function clearCurrentKeyCode() {
|
|
currentKey = '';
|
|
currentKeyCode = 0;
|
|
};
|
|
|
|
function _onResize() {
|
|
if (docById('labelDiv').classList.contains('hasKeyboard')) {
|
|
return;
|
|
}
|
|
|
|
if (!platform.androidWebkit) {
|
|
var w = window.innerWidth;
|
|
var h = window.innerHeight;
|
|
} else {
|
|
var w = window.outerWidth;
|
|
var h = window.outerHeight;
|
|
}
|
|
|
|
var smallSide = Math.min(w, h);
|
|
|
|
if (smallSide < cellSize * 11) {
|
|
var mobileSize = true;
|
|
if (w < cellSize * 10) {
|
|
turtleBlocksScale = smallSide / (cellSize * 11);
|
|
} else {
|
|
turtleBlocksScale = Math.max(smallSide / (cellSize * 11), 0.75);
|
|
}
|
|
} else {
|
|
var mobileSize = false;
|
|
if (w / 1200 > h / 900) {
|
|
turtleBlocksScale = w / 1200;
|
|
} else {
|
|
turtleBlocksScale = h / 900;
|
|
}
|
|
}
|
|
|
|
stage.scaleX = turtleBlocksScale;
|
|
stage.scaleY = turtleBlocksScale;
|
|
|
|
stage.canvas.width = w;
|
|
stage.canvas.height = h;
|
|
|
|
/*
|
|
console.log('Resize: scale ' + turtleBlocksScale +
|
|
', windowW ' + w + ', windowH ' + h +
|
|
', canvasW ' + canvas.width + ', canvasH ' + canvas.height +
|
|
', screenW ' + screen.width + ', screenH ' + screen.height);
|
|
*/
|
|
turtles.setScale(turtleBlocksScale);
|
|
blocks.setScale(turtleBlocksScale);
|
|
boundary.setScale(w, h, turtleBlocksScale);
|
|
palettes.setScale(turtleBlocksScale);
|
|
trashcan.resizeEvent(turtleBlocksScale);
|
|
_setupAndroidToolbar(mobileSize);
|
|
|
|
// Reposition coordinate grids.
|
|
cartesianBitmap.x = (canvas.width / (2 * turtleBlocksScale)) - (600);
|
|
cartesianBitmap.y = (canvas.height / (2 * turtleBlocksScale)) - (450);
|
|
polarBitmap.x = (canvas.width / (2 * turtleBlocksScale)) - (600);
|
|
polarBitmap.y = (canvas.height / (2 * turtleBlocksScale)) - (450);
|
|
update = true;
|
|
|
|
// Setup help now that we have calculated turtleBlocksScale.
|
|
_showHelp(true);
|
|
|
|
// Hide palette icons on mobile
|
|
if (mobileSize) {
|
|
palettes.setMobile(true);
|
|
palettes.hide();
|
|
} else {
|
|
palettes.setMobile(false);
|
|
palettes.show();
|
|
palettes.bringToTop();
|
|
}
|
|
|
|
for (var turtle = 0; turtle < turtles.turtleList.length; turtle++) {
|
|
turtles.turtleList[turtle].doClear(false, false);
|
|
}
|
|
|
|
var artcanvas = document.getElementById("overlayCanvas");
|
|
artcanvas.width = w;
|
|
artcanvas.height = h;
|
|
};
|
|
|
|
window.onresize = function () {
|
|
_onResize();
|
|
};
|
|
|
|
function _restoreTrash() {
|
|
// Restore last stack pushed to trashStack.
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
refreshCanvas();
|
|
|
|
var dx = 0;
|
|
var dy = -cellSize * 3; // Reposition blocks about trash area.
|
|
|
|
if (blocks.trashStacks.length === 0) {
|
|
console.log('Trash is empty--nothing to do');
|
|
return;
|
|
}
|
|
|
|
var thisBlock = blocks.trashStacks.pop();
|
|
|
|
// Restore drag group in trash
|
|
blocks.findDragGroup(thisBlock);
|
|
for (var b = 0; b < blocks.dragGroup.length; b++) {
|
|
var blk = blocks.dragGroup[b];
|
|
// console.log('Restoring ' + blocks.blockList[blk].name + ' from the trash.');
|
|
blocks.blockList[blk].trash = false;
|
|
blocks.moveBlockRelative(blk, dx, dy);
|
|
blocks.blockList[blk].show();
|
|
}
|
|
|
|
blocks.raiseStackToTop(thisBlock);
|
|
|
|
if (blocks.blockList[thisBlock].name === 'start' || blocks.blockList[thisBlock].name === 'drum') {
|
|
var turtle = blocks.blockList[thisBlock].value;
|
|
turtles.turtleList[turtle].trash = false;
|
|
turtles.turtleList[turtle].container.visible = true;
|
|
} else if (blocks.blockList[thisBlock].name === 'action') {
|
|
// We need to add a palette entry for this action.
|
|
// But first we need to ensure we have a unqiue name,
|
|
// as the name could have been taken in the interim.
|
|
var actionArg = blocks.blockList[blocks.blockList[thisBlock].connections[1]];
|
|
if (actionArg != null) {
|
|
var oldName = actionArg.value;
|
|
// Mark the action block as still being in the
|
|
// trash so that its name won't be considered when
|
|
// looking for a unique name.
|
|
blocks.blockList[thisBlock].trash = true;
|
|
var uniqueName = blocks.findUniqueActionName(oldName);
|
|
blocks.blockList[thisBlock].trash = false;
|
|
|
|
if (uniqueName !== actionArg) {
|
|
console.log('renaming action when restoring from trash. old name: ' + oldName + ' unique name: ' + uniqueName);
|
|
|
|
actionArg.value = uniqueName;
|
|
|
|
var label = actionArg.value.toString();
|
|
if (label.length > 8) {
|
|
label = label.substr(0, 7) + '...';
|
|
}
|
|
actionArg.text.text = label;
|
|
|
|
if (actionArg.label != null) {
|
|
actionArg.label.value = uniqueName;
|
|
}
|
|
|
|
actionArg.container.updateCache();
|
|
|
|
// Check the drag group to ensure any do
|
|
// blocks are updated (in case of recursion).
|
|
for (var b = 0; b < blocks.dragGroup.length; b++) {
|
|
var me = blocks.blockList[blocks.dragGroup[b]];
|
|
if (['nameddo', 'nameddoArg', 'namedcalc', 'namedcalcArg'].indexOf(me.name) !== -1 && me.privateData === oldName) {
|
|
console.log('reassigning nameddo to ' + uniqueName);
|
|
me.privateData = uniqueName;
|
|
me.value = uniqueName;
|
|
|
|
var label = me.value.toString();
|
|
if (label.length > 8) {
|
|
label = label.substr(0, 7) + '...';
|
|
}
|
|
me.text.text = label;
|
|
me.overrideName = label;
|
|
me.regenerateArtwork();
|
|
me.container.updateCache();
|
|
}
|
|
}
|
|
}
|
|
|
|
var actionName = actionArg.value;
|
|
if (actionName !== _('action')) {
|
|
// blocks.checkPaletteEntries('action');
|
|
console.log('FIXME: Check for unique action name here');
|
|
}
|
|
}
|
|
}
|
|
|
|
blocks.refreshCanvas();
|
|
};
|
|
|
|
function _deleteBlocksBox() {
|
|
clearBox.show(turtleBlocksScale);
|
|
};
|
|
|
|
function _doUtilityBox() {
|
|
utilityBox.init(turtleBlocksScale, utilityButton.x - 27, utilityButton.y, _makeButton);
|
|
};
|
|
|
|
function sendAllToTrash(addStartBlock, doNotSave) {
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
refreshCanvas();
|
|
|
|
var dx = 0;
|
|
var dy = cellSize * 3;
|
|
for (var blk in blocks.blockList) {
|
|
// If this block is at the top of a stack, push it
|
|
// onto the trashStacks list.
|
|
if (blocks.blockList[blk].connections[0] == null) {
|
|
blocks.trashStacks.push(blk);
|
|
}
|
|
|
|
if (blocks.blockList[blk].name === 'start' || blocks.blockList[blk].name === 'drum') {
|
|
console.log('start blk ' + blk + ' value is ' + blocks.blockList[blk].value)
|
|
var turtle = blocks.blockList[blk].value;
|
|
if (!blocks.blockList[blk].trash && turtle != null) {
|
|
console.log('sending turtle ' + turtle + ' to trash');
|
|
turtles.turtleList[turtle].trash = true;
|
|
turtles.turtleList[turtle].container.visible = false;
|
|
}
|
|
} else if (blocks.blockList[blk].name === 'action') {
|
|
if (!blocks.blockList[blk].trash) {
|
|
blocks.deleteActionBlock(blocks.blockList[blk]);
|
|
}
|
|
}
|
|
|
|
blocks.blockList[blk].trash = true;
|
|
blocks.moveBlockRelative(blk, dx, dy);
|
|
blocks.blockList[blk].hide();
|
|
}
|
|
|
|
if (addStartBlock) {
|
|
blocks.loadNewBlocks(DATAOBJS);
|
|
} else if (!doNotSave) {
|
|
// Overwrite session data too.
|
|
saveLocally();
|
|
}
|
|
|
|
update = true;
|
|
};
|
|
|
|
function _changePaletteVisibility() {
|
|
if (palettes.visible) {
|
|
palettes.hide();
|
|
} else {
|
|
palettes.show();
|
|
palettes.bringToTop();
|
|
}
|
|
};
|
|
|
|
function _changeBlockVisibility() {
|
|
if (blocks.visible) {
|
|
logo.hideBlocks();
|
|
palettes.hide();
|
|
} else {
|
|
if (chartBitmap != null) {
|
|
stage.removeChild(chartBitmap);
|
|
chartBitmap = null;
|
|
}
|
|
logo.showBlocks();
|
|
palettes.show();
|
|
palettes.bringToTop();
|
|
}
|
|
|
|
// Combine block and palette visibility into one button.
|
|
// _changePaletteVisibility();
|
|
};
|
|
|
|
function _toggleCollapsibleStacks() {
|
|
if (blocks.visible) {
|
|
console.log('calling toggleCollapsibles');
|
|
blocks.toggleCollapsibles();
|
|
}
|
|
};
|
|
|
|
function onStopTurtle() {
|
|
// TODO: plugin support
|
|
if (stopTurtleContainer.visible) {
|
|
_hideStopButton();
|
|
}
|
|
};
|
|
|
|
function onRunTurtle() {
|
|
// TODO: plugin support
|
|
// If the stop button is hidden, show it.
|
|
if (!stopTurtleContainer.visible) {
|
|
_showStopButton();
|
|
}
|
|
};
|
|
|
|
function refreshCanvas() {
|
|
update = true;
|
|
};
|
|
|
|
function __tick(event) {
|
|
// This set makes it so the stage only re-renders when an
|
|
// event handler indicates a change has happened.
|
|
if (update) {
|
|
update = false; // Only update once
|
|
stage.update(event);
|
|
}
|
|
};
|
|
|
|
function _doOpenSamples() {
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
localStorage.setItem('isMatrixHidden', docById('ptmDiv').style.visibility);
|
|
localStorage.setItem('isStaircaseHidden', docById('pscDiv').style.visibility);
|
|
localStorage.setItem('isPitchDrumMatrixHidden', docById('pdmDiv').style.visibility);
|
|
localStorage.setItem('isRhythmRulerHidden', docById('rulerDiv').style.visibility);
|
|
localStorage.setItem('isModeWidgetHidden', docById('modeDiv').style.visibility);
|
|
localStorage.setItem('isSliderHidden', docById('sliderDiv').style.visibility);
|
|
localStorage.setItem('isTempoHidden', docById('tempoDiv').style.visibility);
|
|
|
|
if (docById('ptmDiv').style.visibility !== 'hidden') {
|
|
docById('ptmDiv').style.visibility = 'hidden';
|
|
docById('ptmTableDiv').style.visibility = 'hidden';
|
|
docById('ptmButtonsDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('pdmDiv').style.visibility !== 'hidden') {
|
|
docById('pdmDiv').style.visibility = 'hidden';
|
|
docById('pdmButtonsDiv').style.visibility = 'hidden';
|
|
docById('pdmTableDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('rulerDiv').style.visibility !== 'hidden') {
|
|
docById('rulerDiv').style.visibility = 'hidden';
|
|
docById('rulerTableDiv').style.visibility = 'hidden';
|
|
docById('rulerButtonsDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('pscDiv').style.visibility !== 'hidden') {
|
|
docById('pscDiv').style.visibility = 'hidden';
|
|
docById('pscTableDiv').style.visibility = 'hidden';
|
|
docById('pscButtonsDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('statusDiv').style.visibility !== 'hidden') {
|
|
docById('statusDiv').style.visibility = 'hidden';
|
|
docById('statusButtonsDiv').style.visibility = 'hidden';
|
|
docById('statusTableDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('sliderDiv').style.visibility !== 'hidden') {
|
|
docById('sliderDiv').style.visibility = 'hidden';
|
|
docById('sliderButtonsDiv').style.visibility = 'hidden';
|
|
docById('sliderTableDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('modeDiv').style.visibility !== 'hidden') {
|
|
docById('modeDiv').style.visibility = 'hidden';
|
|
docById('modeButtonsDiv').style.visibility = 'hidden';
|
|
docById('modeTableDiv').style.visibility = 'hidden';
|
|
}
|
|
|
|
if (docById('tempoDiv').style.visibility !== 'hidden') {
|
|
if (logo.tempo != null) {
|
|
logo.tempo.hide();
|
|
}
|
|
}
|
|
}
|
|
|
|
localStorage.setItem('isStatusHidden', docById('statusDiv').style.visibility);
|
|
|
|
logo.doStopTurtle();
|
|
helpContainer.visible = false;
|
|
docById('helpElem').style.visibility = 'hidden';
|
|
console.log('save locally');
|
|
saveLocally();
|
|
thumbnails.show()
|
|
};
|
|
|
|
function doSave() {
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
console.log('Saving .tb file');
|
|
var name = 'My Project';
|
|
download(name + '.tb', 'data:text/plain;charset=utf-8,' + prepareExport());
|
|
} else {
|
|
saveBox.init(turtleBlocksScale, saveButton.x - 27, saveButton.y - 97, _makeButton);
|
|
}
|
|
};
|
|
|
|
function doSaveTB() {
|
|
var filename = prompt('Filename:', 'untitled.tb'); // default filename = untitled
|
|
if (filename != null) {
|
|
if (fileExt(filename) !== 'tb') {
|
|
filename += '.tb';
|
|
}
|
|
download(filename, 'data:text/plain;charset=utf-8,' + encodeURIComponent(prepareExport()));
|
|
}
|
|
};
|
|
|
|
function doSaveSVG() {
|
|
var filename = prompt('Filename:', 'untitled.svg');
|
|
if (filename != null) {
|
|
if (fileExt(filename) !== 'svg') {
|
|
filename += '.svg';
|
|
}
|
|
var svg = doSVG(logo.canvas, logo, logo.turtles, logo.canvas.width, logo.canvas.height, 1.0);
|
|
download(filename, 'data:image/svg+xml;utf8,' + svg, filename, '"width=' + logo.canvas.width + ', height=' + logo.canvas.height + '"');
|
|
}
|
|
};
|
|
|
|
function doSavePNG() {
|
|
alert("Unavailable at the moment");
|
|
//var filename = prompt('Filename:', 'untitled.png');
|
|
//if (fileExt(filename) !== 'png') {
|
|
// filename += '.png';
|
|
//}
|
|
//download(filename, 'data:text/plain;charset=utf-8,' + encodeURIComponent(prepareExport()));
|
|
};
|
|
|
|
function doUploadToPlanet() {
|
|
saveLocally();
|
|
thumbnails.show()
|
|
};
|
|
|
|
function doShareOnFacebook() {
|
|
alert("Facebook Sharing : disabled"); // remove when add fb share link
|
|
// add code for facebook share link
|
|
};
|
|
|
|
function doLoad() {
|
|
console.log('Loading .tb file');
|
|
document.querySelector('#myOpenFile').focus();
|
|
document.querySelector('#myOpenFile').click();
|
|
window.scroll(0, 0);
|
|
};
|
|
|
|
function _doLilypond() {
|
|
// Show busy cursor.
|
|
document.body.style.cursor = 'wait';
|
|
|
|
console.log('Saving .ly file');
|
|
// Suppress music and turtle output when generating
|
|
// Lilypond output.
|
|
logo.runningLilypond = true;
|
|
logo.lilypondOutput = LILYPONDHEADER;
|
|
logo.lilypondNotes = {};
|
|
for (var turtle = 0; turtle < turtles.turtleList.length; turtle++) {
|
|
logo.lilypondStaging[turtle] = [];
|
|
turtles.turtleList[turtle].doClear(true, true);
|
|
}
|
|
logo.runLogoCommands();
|
|
};
|
|
|
|
window.prepareExport = prepareExport;
|
|
window.saveLocally = saveLocally;
|
|
|
|
function saveLocally() {
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
//sugarizerCompatibility.data.blocks = prepareExport();
|
|
storage = sugarizerCompatibility.data;
|
|
} else {
|
|
storage = localStorage;
|
|
}
|
|
|
|
console.log('overwriting session data');
|
|
|
|
if (storage.currentProject === undefined) {
|
|
try {
|
|
storage.currentProject = 'My Project';
|
|
storage.allProjects = JSON.stringify(['My Project'])
|
|
} catch (e) {
|
|
// Edge case, eg. Firefox localSorage DB corrupted
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
try {
|
|
var p = storage.currentProject;
|
|
storage['SESSION' + p] = prepareExport();
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
|
|
// if (isSVGEmpty(turtles)) {
|
|
// We will use the music icon in these cases.
|
|
// return;
|
|
// }
|
|
|
|
var img = new Image();
|
|
var svgData = doSVG(canvas, logo, turtles, 320, 240, 320 / canvas.width);
|
|
img.onload = function () {
|
|
var bitmap = new createjs.Bitmap(img);
|
|
var bounds = bitmap.getBounds();
|
|
bitmap.cache(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
try {
|
|
storage['SESSIONIMAGE' + p] = bitmap.getCacheDataURL();
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
};
|
|
|
|
img.src = 'data:image/svg+xml;base64,' +
|
|
window.btoa(unescape(encodeURIComponent(svgData)));
|
|
// console.log(img.src);
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
sugarizerCompatibility.saveLocally();
|
|
}
|
|
};
|
|
|
|
function runProject(env){
|
|
console.log("Running Project from Event");
|
|
document.removeEventListener("finishedLoading", runProject);
|
|
setTimeout(function () {
|
|
console.log("Run");
|
|
_changeBlockVisibility();
|
|
_doFastButton(env);
|
|
}, 5000);
|
|
}
|
|
|
|
function loadProject(projectName, run, env) {
|
|
//set default value of run
|
|
run = typeof run !== 'undefined' ? run : false;
|
|
// Show busy cursor.
|
|
document.body.style.cursor = 'wait';
|
|
// palettes.updatePalettes();
|
|
setTimeout(function () {
|
|
if (fileExt(projectName) !== 'tb')
|
|
{
|
|
projectName += '.tb';
|
|
}
|
|
|
|
try {
|
|
try {
|
|
httpGet(null);
|
|
console.log('running from server or the user can access to examples.');
|
|
server = true;
|
|
} catch (e) {
|
|
console.log('running from filesystem or the connection isnt secure');
|
|
server = false;
|
|
}
|
|
|
|
if (server) {
|
|
var rawData = httpGet(projectName);
|
|
var cleanData = rawData.replace('\n', '');
|
|
}
|
|
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
|
|
var obj = JSON.parse(cleanData);
|
|
blocks.loadNewBlocks(obj);
|
|
saveLocally();
|
|
} catch (e) {
|
|
console.log(e);
|
|
loadStartWrapper(_loadStart);
|
|
}
|
|
|
|
// Restore default cursor
|
|
document.body.style.cursor = 'default';
|
|
update = true;
|
|
}, 200);
|
|
|
|
if (run && firstRun) {
|
|
if (document.addEventListener) {
|
|
document.addEventListener('finishedLoading', function (){runProject(env);}, false);
|
|
} else {
|
|
document.attachEvent('finishedLoading', function (){runProject(env);});
|
|
}
|
|
}
|
|
firstRun = false;
|
|
};
|
|
|
|
function loadRawProject(data) {
|
|
console.log('loadRawProject ' + data);
|
|
document.body.style.cursor = 'wait';
|
|
_allClear();
|
|
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
|
|
var obj = JSON.parse(data);
|
|
blocks.loadNewBlocks(obj);
|
|
document.body.style.cursor = 'default';
|
|
};
|
|
|
|
function saveProject(projectName) {
|
|
// palettes.updatePalettes();
|
|
// Show busy cursor.
|
|
document.body.style.cursor = 'wait';
|
|
setTimeout(function () {
|
|
var punctuationless = projectName.replace(/['!"#$%&\\'()\*+,\-\.\/:;<=>?@\[\\\]\^`{|}~']/g, '');
|
|
projectName = punctuationless.replace(/ /g, '_');
|
|
if (fileExt(projectName) !== 'tb') {
|
|
projectName += '.tb';
|
|
}
|
|
try {
|
|
// Post the project
|
|
var returnValue = httpPost('MusicBlocks_'+projectName, prepareExport());
|
|
errorMsg('Saved ' + projectName + ' to ' + window.location.host);
|
|
|
|
var img = new Image();
|
|
var svgData = doSVG(canvas, logo, turtles, 320, 240, 320 / canvas.width);
|
|
img.onload = function () {
|
|
var bitmap = new createjs.Bitmap(img);
|
|
var bounds = bitmap.getBounds();
|
|
bitmap.cache(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
// and base64-encoded png
|
|
httpPost(('MusicBlocks_'+projectName).replace('.tb', '.b64'), bitmap.getCacheDataURL());
|
|
};
|
|
|
|
img.src = 'data:image/svg+xml;base64,' + window.btoa(
|
|
unescape(encodeURIComponent(svgData)));
|
|
// Restore default cursor
|
|
document.body.style.cursor = 'default';
|
|
return returnValue;
|
|
} catch (e) {
|
|
console.log(e);
|
|
// Restore default cursor
|
|
document.body.style.cursor = 'default';
|
|
return;
|
|
}
|
|
}, 200);
|
|
};
|
|
|
|
// Calculate time such that no matter how long it takes to
|
|
// load the program, the loading animation will cycle at least
|
|
// once.
|
|
function loadStartWrapper(func, arg1, arg2, arg3) {
|
|
var time1 = new Date();
|
|
func(arg1, arg2, arg3);
|
|
|
|
var time2 = new Date();
|
|
var elapsedTime = time2.getTime() - time1.getTime();
|
|
var timeLeft = Math.max(6000 - elapsedTime);
|
|
setTimeout(showContents, timeLeft);
|
|
};
|
|
|
|
// Hides the loading animation and unhides the background.
|
|
function showContents(){
|
|
docById('loading-image-container').style.display = 'none';
|
|
// docById('canvas').style.display = 'none';
|
|
docById('hideContents').style.display = 'block';
|
|
};
|
|
|
|
function _loadStart() {
|
|
// where to put this?
|
|
// palettes.updatePalettes();
|
|
console.log('LOAD START')
|
|
justLoadStart = function () {
|
|
console.log('loading start and a matrix');
|
|
blocks.loadNewBlocks(DATAOBJS);
|
|
};
|
|
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
storage = sugarizerCompatibility.data;
|
|
}
|
|
else {
|
|
storage = localStorage;
|
|
}
|
|
|
|
sessionData = null;
|
|
// Try restarting where we were when we hit save.
|
|
var currentProject = storage.currentProject;
|
|
sessionData = storage['SESSION' + currentProject];
|
|
if (sessionData) {
|
|
try {
|
|
if (sessionData === 'undefined' || sessionData === '[]') {
|
|
console.log('empty session found: loading start');
|
|
justLoadStart();
|
|
} else {
|
|
console.log('restoring session: ' + sessionData);
|
|
// First, hide the palettes as they will need updating.
|
|
for (var name in blocks.palettes.dict) {
|
|
blocks.palettes.dict[name].hideMenu(true);
|
|
}
|
|
|
|
blocks.loadNewBlocks(JSON.parse(sessionData));
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
} else {
|
|
justLoadStart();
|
|
}
|
|
|
|
update = true;
|
|
|
|
|
|
};
|
|
|
|
function hideMsgs() {
|
|
errorMsgText.parent.visible = false;
|
|
if (errorMsgArrow != null) {
|
|
errorMsgArrow.removeAllChildren();
|
|
refreshCanvas();
|
|
}
|
|
|
|
msgText.parent.visible = false;
|
|
for (var i in errorArtwork) {
|
|
errorArtwork[i].visible = false;
|
|
}
|
|
};
|
|
|
|
function textMsg(msg) {
|
|
if (msgText == null) {
|
|
// The container may not be ready yet... so do nothing
|
|
return;
|
|
}
|
|
var msgContainer = msgText.parent;
|
|
msgContainer.visible = true;
|
|
msgText.text = msg;
|
|
msgContainer.updateCache();
|
|
stage.setChildIndex(msgContainer, stage.getNumChildren() - 1);
|
|
};
|
|
|
|
function errorMsg(msg, blk, text) {
|
|
_hideStopButton(); //Hide the button, as the program is going to be terminated
|
|
if (errorMsgText == null) {
|
|
// The container may not be ready yet... so do nothing
|
|
return;
|
|
}
|
|
if (blk !== undefined && blk != null && !blocks.blockList[blk].collapsed) {
|
|
var fromX = (canvas.width - 1000) / 2;
|
|
var fromY = 128;
|
|
var toX = blocks.blockList[blk].container.x + blocksContainer.x;
|
|
var toY = blocks.blockList[blk].container.y + blocksContainer.y;
|
|
|
|
if (errorMsgArrow == null) {
|
|
errorMsgArrow = new createjs.Container();
|
|
stage.addChild(errorMsgArrow);
|
|
}
|
|
|
|
var line = new createjs.Shape();
|
|
errorMsgArrow.addChild(line);
|
|
line.graphics.setStrokeStyle(4).beginStroke('#ff0031').moveTo(fromX, fromY).lineTo(toX, toY);
|
|
stage.setChildIndex(errorMsgArrow, stage.getNumChildren() - 1);
|
|
|
|
var angle = Math.atan2(toX - fromX, fromY - toY) / Math.PI * 180;
|
|
var head = new createjs.Shape();
|
|
errorMsgArrow.addChild(head);
|
|
head.graphics.setStrokeStyle(4).beginStroke('#ff0031').moveTo(-10, 18).lineTo(0, 0).lineTo(10, 18);
|
|
head.x = toX;
|
|
head.y = toY;
|
|
head.rotation = angle;
|
|
}
|
|
|
|
switch (msg) {
|
|
case NOMICERRORMSG:
|
|
errorArtwork['nomicrophone'].visible = true;
|
|
stage.setChildIndex(errorArtwork['nomicrophone'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NOSTRINGERRORMSG:
|
|
errorArtwork['notastring'].visible = true;
|
|
stage.setChildIndex(errorArtwork['notastring'], stage.getNumChildren() - 1);
|
|
break;
|
|
case EMPTYHEAPERRORMSG:
|
|
errorArtwork['emptyheap'].visible = true;
|
|
stage.setChildIndex(errorArtwork['emptyheap'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NOSQRTERRORMSG:
|
|
errorArtwork['negroot'].visible = true;
|
|
stage.setChildIndex(errorArtwork['negroot'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NOACTIONERRORMSG:
|
|
if (text == null) {
|
|
text = 'foo';
|
|
}
|
|
errorArtwork['nostack'].children[1].text = text;
|
|
errorArtwork['nostack'].visible = true;
|
|
errorArtwork['nostack'].updateCache();
|
|
stage.setChildIndex(errorArtwork['nostack'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NOBOXERRORMSG:
|
|
if (text == null) {
|
|
text = 'foo';
|
|
}
|
|
errorArtwork['emptybox'].children[1].text = text;
|
|
errorArtwork['emptybox'].visible = true;
|
|
errorArtwork['emptybox'].updateCache();
|
|
stage.setChildIndex(errorArtwork['emptybox'], stage.getNumChildren() - 1);
|
|
break;
|
|
case ZERODIVIDEERRORMSG:
|
|
errorArtwork['zerodivide'].visible = true;
|
|
stage.setChildIndex(errorArtwork['zerodivide'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NANERRORMSG:
|
|
errorArtwork['notanumber'].visible = true;
|
|
stage.setChildIndex(errorArtwork['notanumber'], stage.getNumChildren() - 1);
|
|
break;
|
|
case NOINPUTERRORMSG:
|
|
errorArtwork['noinput'].visible = true;
|
|
stage.setChildIndex(errorArtwork['noinput'], stage.getNumChildren() - 1);
|
|
break;
|
|
default:
|
|
var errorMsgContainer = errorMsgText.parent;
|
|
errorMsgContainer.visible = true;
|
|
errorMsgText.text = msg;
|
|
stage.setChildIndex(errorMsgContainer, stage.getNumChildren() - 1);
|
|
errorMsgContainer.updateCache();
|
|
break;
|
|
}
|
|
|
|
update = true;
|
|
};
|
|
|
|
function _hideCartesian() {
|
|
cartesianBitmap.visible = false;
|
|
cartesianBitmap.updateCache();
|
|
update = true;
|
|
};
|
|
|
|
function _showCartesian() {
|
|
cartesianBitmap.visible = true;
|
|
cartesianBitmap.updateCache();
|
|
update = true;
|
|
};
|
|
|
|
function _hidePolar() {
|
|
polarBitmap.visible = false;
|
|
polarBitmap.updateCache();
|
|
update = true;
|
|
};
|
|
|
|
function _showPolar() {
|
|
polarBitmap.visible = true;
|
|
polarBitmap.updateCache();
|
|
update = true;
|
|
};
|
|
|
|
function pasteStack() {
|
|
blocks.pasteStack();
|
|
};
|
|
|
|
function prepareExport() {
|
|
// We don't save blocks in the trash, so we need to
|
|
// consolidate the block list and remap the connections.
|
|
var blockMap = [];
|
|
var hasMatrixDataBlock = false;
|
|
for (var blk = 0; blk < blocks.blockList.length; blk++) {
|
|
var myBlock = blocks.blockList[blk];
|
|
if (myBlock.trash) {
|
|
// Don't save blocks in the trash.
|
|
continue;
|
|
}
|
|
blockMap.push(blk);
|
|
}
|
|
|
|
var data = [];
|
|
for (var blk = 0; blk < blocks.blockList.length; blk++) {
|
|
var myBlock = blocks.blockList[blk];
|
|
if (myBlock.trash) {
|
|
// Don't save blocks in the trash.
|
|
continue;
|
|
}
|
|
|
|
if (myBlock.isValueBlock() || myBlock.name === 'loadFile') {
|
|
// FIX ME: scale image if it exceeds a maximum size.
|
|
var args = {
|
|
'value': myBlock.value
|
|
};
|
|
} else if (myBlock.name === 'start' || myBlock.name === 'drum') {
|
|
// Find the turtle associated with this block.
|
|
var turtle = turtles.turtleList[myBlock.value];
|
|
if (turtle == null) {
|
|
var args = {
|
|
'collapsed': false,
|
|
'xcor': 0,
|
|
'ycor': 0,
|
|
'heading': 0,
|
|
'color': 0,
|
|
'shade': 50,
|
|
'pensize': 5,
|
|
'grey': 100
|
|
};
|
|
} else {
|
|
var args = {
|
|
'collapsed': myBlock.collapsed,
|
|
'xcor': turtle.x,
|
|
'ycor': turtle.y,
|
|
'heading': turtle.orientation,
|
|
'color': turtle.color,
|
|
'shade': turtle.value,
|
|
'pensize': turtle.stroke,
|
|
'grey': turtle.chroma
|
|
};
|
|
}
|
|
} else if (myBlock.name === 'action') {
|
|
var args = {
|
|
'collapsed': myBlock.collapsed
|
|
}
|
|
} else if(myBlock.name === 'matrix') {
|
|
var args = {
|
|
'collapsed' : myBlock.collapsed
|
|
}
|
|
} else if(myBlock.name === 'pitchdrummatrix') {
|
|
var args = {
|
|
'collapsed' : myBlock.collapsed
|
|
}
|
|
} else if(myBlock.name === 'status') {
|
|
var args = {
|
|
'collapsed' : myBlock.collapsed
|
|
}
|
|
} else if (myBlock.name === 'namedbox') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'nameddo') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'nameddoArg') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'namedcalc') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'namedcalcArg') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'namedarg') {
|
|
var args = {
|
|
'value': myBlock.privateData
|
|
}
|
|
} else if (myBlock.name === 'matrixData') {
|
|
var args = {
|
|
'notes': window.savedMatricesNotes, 'count': window.savedMatricesCount
|
|
}
|
|
hasMatrixDataBlock = true;
|
|
} else {
|
|
var args = {}
|
|
}
|
|
|
|
connections = [];
|
|
for (var c = 0; c < myBlock.connections.length; c++) {
|
|
var mapConnection = blockMap.indexOf(myBlock.connections[c]);
|
|
if (myBlock.connections[c] == null || mapConnection === -1) {
|
|
connections.push(null);
|
|
} else {
|
|
connections.push(mapConnection);
|
|
}
|
|
}
|
|
data.push([blockMap.indexOf(blk), [myBlock.name, args], myBlock.container.x, myBlock.container.y, connections]);
|
|
}
|
|
|
|
return JSON.stringify(data);
|
|
};
|
|
|
|
function doOpenPlugin() {
|
|
// Click on the plugin open chooser in the DOM (.json).
|
|
pluginChooser.focus();
|
|
pluginChooser.click();
|
|
};
|
|
|
|
function saveToFile() {
|
|
var filename = prompt('Filename:');
|
|
if (fileExt(filename) !== 'tb') {
|
|
filename += '.tb';
|
|
}
|
|
download(filename, 'data:text/plain;charset=utf-8,' + encodeURIComponent(prepareExport()));
|
|
};
|
|
|
|
function _hideStopButton() {
|
|
// stopTurtleContainer.x = stopTurtleContainerX;
|
|
// stopTurtleContainer.y = stopTurtleContainerY;
|
|
stopTurtleContainer.visible = false;
|
|
};
|
|
|
|
function _showStopButton() {
|
|
// stopTurtleContainer.x = onscreenButtons[0].x;
|
|
// stopTurtleContainer.y = onscreenButtons[0].y;
|
|
stopTurtleContainer.visible = true;
|
|
};
|
|
|
|
function blinkPasteButton(bitmap) {
|
|
function handleComplete() {
|
|
createjs.Tween.get(bitmap).to({alpha:1, visible:true}, 500);
|
|
};
|
|
|
|
createjs.Tween.get(bitmap).to({alpha:0, visible:false}, 1000).call(
|
|
handleComplete);
|
|
};
|
|
|
|
function updatePasteButton() {
|
|
if (pasteImage === null) {
|
|
|
|
var img = new Image();
|
|
|
|
img.onload = function () {
|
|
var originalSize = 55; // this is the original svg size
|
|
var halfSize = Math.floor(cellSize / 2);
|
|
|
|
var bitmap = new createjs.Bitmap(img);
|
|
if (cellSize !== originalSize) {
|
|
bitmap.scaleX = cellSize / originalSize;
|
|
bitmap.scaleY = cellSize / originalSize;
|
|
}
|
|
bitmap.regX = halfSize / bitmap.scaleX;
|
|
bitmap.regY = halfSize / bitmap.scaleY;
|
|
pasteContainer.addChild(bitmap);
|
|
pasteImage = bitmap;
|
|
|
|
update = true;
|
|
};
|
|
|
|
img.src = 'header-icons/paste-button.svg';
|
|
} else {
|
|
blinkPasteButton(pasteImage);
|
|
}
|
|
};
|
|
|
|
function _setupAndroidToolbar(showPalettesPopover) {
|
|
if (headerContainer !== undefined) {
|
|
stage.removeChild(headerContainer);
|
|
for (var i in onscreenButtons) {
|
|
stage.removeChild(onscreenButtons[i]);
|
|
}
|
|
}
|
|
|
|
headerContainer = new createjs.Shape();
|
|
headerContainer.graphics.f(platformColor.header).r(0, 0, screen.width / turtleBlocksScale, cellSize);
|
|
|
|
if (platformColor.doHeaderShadow) {
|
|
headerContainer.shadow = new createjs.Shadow('#777', 0, 2, 2);
|
|
}
|
|
|
|
stage.addChild(headerContainer);
|
|
|
|
// Buttons used when running turtle programs
|
|
// name / onpress function / label / onlongpress function / onextralongpress function / onlongpress icon / onextralongpress icon
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
var buttonNames = [
|
|
['run', _doFastButton, _('Run fast / long press to run slowly / extra-long press to run music slowly'), _doSlowButton, _doSlowMusicButton, 'slow-button', 'slow-music-button'],
|
|
['step', _doStepButton, _('Run step by step'), null, null, null, null],
|
|
['step-music', _doStepMusicButton, _('Run note by note'), null, null, null, null],
|
|
['stop-turtle', doStopButton, _('Stop'), null, null, null, null],
|
|
['clear', _allClear, _('Clean'), null, null, null, null],
|
|
// ['palette', _changePaletteVisibility, _('Show/hide palettes'), null, null, null, null],
|
|
['hide-blocks', _changeBlockVisibility, _('Show/hide blocks'), null, null, null, null],
|
|
['collapse-blocks', _toggleCollapsibleStacks, _('Expand/collapse collapsable blocks'), null, null, null, null],
|
|
['go-home', _findBlocks, _('Home'), null, null, null, null],
|
|
['help', _showHelp, _('Help'), null, null, null, null]
|
|
];
|
|
} else {
|
|
var buttonNames = [
|
|
['run', _doFastButton, _('Run fast / long press to run slowly'), _doSlowButton, null, 'slow-button', null],
|
|
['step', _doStepButton, _('Run step by step'), null, null, null, null],
|
|
['stop-turtle', doStopButton, _('Stop'), null, null, null, null],
|
|
['clear', _allClear, _('Clean'), null, null, null, null],
|
|
['hide-blocks', _changeBlockVisibility, _('Show/hide blocks'), null, null, null, null],
|
|
['collapse-blocks', _toggleCollapsibleStacks, _('Expand/collapse collapsable blocks'), null, null, null, null],
|
|
['go-home', _findBlocks, _('Home'), null, null, null, null],
|
|
['help', _showHelp, _('Help'), null, null, null, null]
|
|
];
|
|
}
|
|
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
buttonNames.push(['sugarizer-stop', function () {
|
|
sugarizerCompatibility.data.blocks = prepareExport();
|
|
sugarizerCompatibility.saveLocally(function () {
|
|
sugarizerCompatibility.sugarizerStop();
|
|
});
|
|
}, "Stop", null, null, null, null])
|
|
}
|
|
|
|
if (showPalettesPopover) {
|
|
buttonNames.unshift(['popdown-palette', doPopdownPalette])
|
|
}
|
|
|
|
var btnSize = cellSize;
|
|
var x = Math.floor(btnSize / 2);
|
|
var y = x;
|
|
var dx = btnSize;
|
|
var dy = 0;
|
|
|
|
for (var i = 0; i < buttonNames.length; i++) {
|
|
if (!getMainToolbarButtonNames(buttonNames[i][0])) {
|
|
console.log('continue');
|
|
continue;
|
|
}
|
|
|
|
var container = _makeButton(buttonNames[i][0] + '-button', buttonNames[i][2], x, y, btnSize, 0);
|
|
_loadButtonDragHandler(container, x, y, buttonNames[i][1], buttonNames[i][3], buttonNames[i][4], buttonNames[i][5], buttonNames[i][6]);
|
|
onscreenButtons.push(container);
|
|
|
|
if (buttonNames[i][0] === 'stop-turtle') {
|
|
stopTurtleContainer = container;
|
|
stopTurtleContainerX = x;
|
|
stopTurtleContainerY = y;
|
|
} else if (buttonNames[i][0] === 'go-home') {
|
|
homeButtonContainers = [];
|
|
homeButtonContainers.push(container);
|
|
homeButtonContainersX = x;
|
|
homeButtonContainersY = y;
|
|
var container2 = _makeButton('go-home-faded-button', _('Home'), x, y, btnSize, 0);
|
|
_loadButtonDragHandler(container2, x, y, buttonNames[i][1], null, null, null, null);
|
|
homeButtonContainers.push(container2);
|
|
onscreenButtons.push(container2);
|
|
homeButtonContainers[0].visible = false;
|
|
homeButtonContainers[1].visible = true;
|
|
boundary.hide();
|
|
blocks.setHomeContainers(homeButtonContainers, boundary);
|
|
}
|
|
|
|
x += dx;
|
|
y += dy;
|
|
}
|
|
|
|
_setupRightMenu(turtleBlocksScale);
|
|
};
|
|
|
|
function _setupRightMenu(turtleBlocksScale) {
|
|
if (menuContainer !== undefined) {
|
|
stage.removeChild(menuContainer);
|
|
for (var i in onscreenMenu) {
|
|
stage.removeChild(onscreenMenu[i]);
|
|
}
|
|
}
|
|
|
|
// Misc. other buttons
|
|
if (_THIS_IS_MUSIC_BLOCKS_) {
|
|
var menuNames = [
|
|
['planet', _doOpenSamples, _('Load samples from server')],
|
|
['open', doLoad, _('Load project from files')],
|
|
['save', doSave, _('Save project')],
|
|
['lilypond', _doLilypond, _('Save sheet music')],
|
|
['paste-disabled', pasteStack, _('Paste')],
|
|
['Cartesian', _doCartesian, _('Cartesian')],
|
|
['polar', _doPolar, _('Polar')],
|
|
['utility', _doUtilityBox, _('Settings')],
|
|
['empty-trash', _deleteBlocksBox, _('Delete all')],
|
|
['restore-trash', _restoreTrash, _('Undo')]
|
|
];
|
|
} else {
|
|
var menuNames = [
|
|
['planet', _doOpenSamples, _('Load samples from server')],
|
|
['open', doLoad, _('Load project from files')],
|
|
['save', doSave, _('Save project')],
|
|
['paste-disabled', pasteStack, _('Paste')],
|
|
['Cartesian', _doCartesian, _('Cartesian')],
|
|
['polar', _doPolar, _('Polar')],
|
|
['utility', _doUtilityBox, _('Settings')],
|
|
['empty-trash', _deleteBlocksBox, _('Delete all')],
|
|
['restore-trash', _restoreTrash, _('Undo')]
|
|
];
|
|
}
|
|
|
|
document.querySelector('#myOpenFile')
|
|
.addEventListener('change', function (event) {
|
|
thumbnails.model.controller.hide();
|
|
});
|
|
|
|
var btnSize = cellSize;
|
|
var x = Math.floor(canvas.width / turtleBlocksScale) - btnSize / 2;
|
|
var y = Math.floor(btnSize / 2);
|
|
|
|
var dx = 0;
|
|
var dy = btnSize;
|
|
|
|
menuContainer = _makeButton('menu-button', '', x, y, btnSize, menuButtonsVisible ? 90 : undefined);
|
|
_loadButtonDragHandler(menuContainer, x, y, _doMenuButton, null, null, null, null);
|
|
|
|
for (var i = 0; i < menuNames.length; i++) {
|
|
if (!getAuxToolbarButtonNames(menuNames[i][0])) {
|
|
continue;
|
|
}
|
|
|
|
x += dx;
|
|
y += dy;
|
|
var container = _makeButton(menuNames[i][0] + '-button', menuNames[i][2], x, y, btnSize, 0);
|
|
_loadButtonDragHandler(container, x, y, menuNames[i][1], null, null, null, null);
|
|
onscreenMenu.push(container);
|
|
if (menuNames[i][0] === 'utility') {
|
|
utilityButton = container;
|
|
} else if (menuNames[i][0] === 'save') {
|
|
saveButton = container;
|
|
}
|
|
|
|
container.visible = false;
|
|
}
|
|
|
|
if (menuButtonsVisible) {
|
|
for (var button in onscreenMenu) {
|
|
onscreenMenu[button].visible = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
function doPopdownPalette() {
|
|
console.log('doPopdownPalette');
|
|
var p = new PopdownPalette(palettes);
|
|
p.popdown();
|
|
};
|
|
|
|
function _showHelp(firstTime) {
|
|
helpIdx = 0;
|
|
|
|
if (firstTime) {
|
|
if (helpContainer == null) {
|
|
helpContainer = new createjs.Container();
|
|
stage.addChild(helpContainer);
|
|
helpContainer.x = 65;
|
|
helpContainer.y = 65;
|
|
|
|
helpContainer.on('click', function (event) {
|
|
var bounds = helpContainer.getBounds();
|
|
if (event.stageY < helpContainer.y + bounds.height / 2) {
|
|
helpContainer.visible = false;
|
|
docById('helpElem').style.visibility = 'hidden';
|
|
} else {
|
|
helpIdx += 1;
|
|
if (helpIdx >= HELPCONTENT.length) {
|
|
helpIdx = 0;
|
|
}
|
|
var imageScale = 55 * turtleBlocksScale;
|
|
helpElem.innerHTML = '<img src ="' + HELPCONTENT[helpIdx][2] + '" style="height:' + imageScale + 'px; width: auto"></img> <h2>' + HELPCONTENT[helpIdx][0] + '</h2><p>' + HELPCONTENT[helpIdx][1] + '</p>';
|
|
}
|
|
update = true;
|
|
});
|
|
|
|
var img = new Image();
|
|
img.onload = function () {
|
|
console.log(turtleBlocksScale);
|
|
var bitmap = new createjs.Bitmap(img);
|
|
/*
|
|
if (turtleBlocksScale > 1) {
|
|
bitmap.scaleX = bitmap.scaleY = bitmap.scale = turtleBlocksScale;
|
|
} else {
|
|
bitmap.scaleX = bitmap.scaleY = bitmap.scale = 1.125;
|
|
}
|
|
*/
|
|
if (helpContainer.children.length > 0) {
|
|
console.log('delete old help container');
|
|
helpContainer.removeChild(helpContainer.children[0]);
|
|
}
|
|
helpContainer.addChild(bitmap)
|
|
|
|
var bounds = helpContainer.getBounds();
|
|
var hitArea = new createjs.Shape();
|
|
hitArea.graphics.beginFill('#FFF').drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
hitArea.x = 0;
|
|
hitArea.y = 0;
|
|
helpContainer.hitArea = hitArea;
|
|
|
|
docById('helpElem').innerHTML = '<img src ="' + HELPCONTENT[helpIdx][2] + '"</img> <h2>' + HELPCONTENT[helpIdx][0] + '</h2><p>' + HELPCONTENT[helpIdx][1] + '</p>';
|
|
if (!doneTour) {
|
|
docById('helpElem').style.visibility = 'visible';
|
|
}
|
|
update = true;
|
|
};
|
|
|
|
img.src = 'images/help-container.svg';
|
|
}
|
|
|
|
var helpElem = docById('helpElem');
|
|
helpElem.style.position = 'absolute';
|
|
helpElem.style.display = 'block';
|
|
helpElem.style.paddingLeft = 20 * turtleBlocksScale + 'px';
|
|
helpElem.style.paddingRight = 20 * turtleBlocksScale + 'px';
|
|
helpElem.style.paddingTop = '0px';
|
|
helpElem.style.paddingBottom = 20 * turtleBlocksScale + 'px';
|
|
helpElem.style.fontSize = 20 + 'px'; // * turtleBlocksScale + 'px';
|
|
helpElem.style.color = '#000000'; // '#ffffff';
|
|
helpElem.style.left = 65 * turtleBlocksScale + 'px';
|
|
helpElem.style.top = 105 * turtleBlocksScale + 'px';
|
|
var w = Math.min(300, 300); // * turtleBlocksScale);
|
|
var h = Math.min(300, 300); // * turtleBlocksScale);
|
|
helpElem.style.width = w + 'px';
|
|
helpElem.style.height = h + 'px';
|
|
|
|
if (turtleBlocksScale > 1) {
|
|
var bitmap = helpContainer.children[0];
|
|
if (bitmap != undefined) {
|
|
// bitmap.scaleX = bitmap.scaleY = bitmap.scale = turtleBlocksScale;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
doneTour = storage.doneTour === 'true';
|
|
|
|
if (firstTime && doneTour) {
|
|
docById('helpElem').style.visibility = 'hidden';
|
|
helpContainer.visible = false;
|
|
} else {
|
|
if (sugarizerCompatibility.isInsideSugarizer()) {
|
|
sugarizerCompatibility.data.doneTour = 'true';
|
|
} else {
|
|
storage.doneTour = 'true';
|
|
}
|
|
docById('helpElem').innerHTML = '<img src ="' + HELPCONTENT[helpIdx][2] + '"</img> <h2>' + HELPCONTENT[helpIdx][0] + '</h2><p>' + HELPCONTENT[helpIdx][1] + '</p>';
|
|
docById('helpElem').style.visibility = 'visible';
|
|
helpContainer.visible = true;
|
|
update = true;
|
|
|
|
// Make sure the palettes and the secondary menus are
|
|
// visible while help is shown.
|
|
palettes.show();
|
|
if (!menuButtonsVisible) {
|
|
doMenuAnimation(1);
|
|
}
|
|
}
|
|
};
|
|
|
|
function _doMenuButton() {
|
|
_doMenuAnimation(1);
|
|
};
|
|
|
|
function _doMenuAnimation() {
|
|
var bitmap = last(menuContainer.children);
|
|
if (bitmap != null) {
|
|
var r = bitmap.rotation;
|
|
createjs.Tween.get(bitmap)
|
|
.to({
|
|
rotation: r
|
|
})
|
|
.to({
|
|
rotation: r + 90
|
|
}, 500);
|
|
} else {
|
|
// Race conditions during load
|
|
setTimeout(_doMenuAnimation, 50);
|
|
}
|
|
|
|
setTimeout(function () {
|
|
if (menuButtonsVisible) {
|
|
menuButtonsVisible = false;
|
|
for (var button in onscreenMenu) {
|
|
onscreenMenu[button].visible = false;
|
|
}
|
|
} else {
|
|
menuButtonsVisible = true;
|
|
for (var button in onscreenMenu) {
|
|
onscreenMenu[button].visible = true;
|
|
}
|
|
}
|
|
update = true;
|
|
}, 500);
|
|
};
|
|
|
|
function _toggleToolbar() {
|
|
buttonsVisible = !buttonsVisible;
|
|
menuContainer.visible = buttonsVisible;
|
|
headerContainer.visible = buttonsVisible;
|
|
for (var button in onscreenButtons) {
|
|
onscreenButtons[button].visible = buttonsVisible;
|
|
}
|
|
|
|
for (var button in onscreenMenu) {
|
|
onscreenMenu[button].visible = buttonsVisible;
|
|
}
|
|
|
|
update = true;
|
|
};
|
|
|
|
function _makeButton(name, label, x, y, size, rotation, parent) {
|
|
var container = new createjs.Container();
|
|
if (name === 'paste-disabled-button') {
|
|
pasteContainer = container;
|
|
}
|
|
|
|
if (parent == undefined) {
|
|
stage.addChild(container);
|
|
} else {
|
|
parent.addChild(container);
|
|
}
|
|
|
|
container.x = x;
|
|
container.y = y;
|
|
|
|
var text = new createjs.Text(label, '14px Sans', '#282828');
|
|
if (container.y < 55) {
|
|
if (container.x < 55) {
|
|
text.textAlign = 'left';
|
|
text.x = -14;
|
|
} else {
|
|
text.textAlign = 'center';
|
|
text.x = 0;
|
|
}
|
|
text.y = 30;
|
|
} else {
|
|
text.textAlign = 'right';
|
|
text.x = -28;
|
|
text.y = 0;
|
|
}
|
|
|
|
text.visible = false;
|
|
|
|
container.on('mouseover', function (event) {
|
|
for (var c = 0; c < container.children.length; c++) {
|
|
if (container.children[c].text != undefined) {
|
|
container.children[c].visible = true;
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
container.on('mouseout', function (event) {
|
|
for (var c = 0; c < container.children.length; c++) {
|
|
if (container.children[c].text != undefined) {
|
|
container.children[c].visible = false;
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
var img = new Image();
|
|
|
|
img.onload = function () {
|
|
var originalSize = 55; // this is the original svg size
|
|
var halfSize = Math.floor(size / 2);
|
|
|
|
var bitmap = new createjs.Bitmap(img);
|
|
if (size !== originalSize) {
|
|
bitmap.scaleX = size / originalSize;
|
|
bitmap.scaleY = size / originalSize;
|
|
}
|
|
|
|
bitmap.regX = halfSize / bitmap.scaleX;
|
|
bitmap.regY = halfSize / bitmap.scaleY;
|
|
if (rotation !== undefined) {
|
|
bitmap.rotation = rotation;
|
|
}
|
|
|
|
container.addChild(bitmap);
|
|
var hitArea = new createjs.Shape();
|
|
hitArea.graphics.beginFill('#FFF').drawEllipse(-halfSize, -halfSize, size, size);
|
|
hitArea.x = 0;
|
|
hitArea.y = 0;
|
|
container.hitArea = hitArea;
|
|
bitmap.cache(0, 0, size, size);
|
|
bitmap.updateCache();
|
|
update = true;
|
|
};
|
|
|
|
img.src = 'header-icons/' + name + '.svg';
|
|
container.addChild(text);
|
|
|
|
return container;
|
|
};
|
|
|
|
function _loadButtonDragHandler(container, ox, oy, action, longAction, extraLongAction, longImg, extraLongImg) {
|
|
// Prevent multiple button presses (i.e., debounce).
|
|
var locked = false;
|
|
|
|
if (longAction === null) {
|
|
longAction = action;
|
|
}
|
|
|
|
if (extraLongAction === null) {
|
|
extraLongAction = longAction;
|
|
}
|
|
|
|
// Long and extra-long press variables declaration
|
|
var pressTimer, pressTimerExtra, isLong = false, isExtraLong = false;
|
|
var formerContainer = container;
|
|
|
|
container.on('mousedown', function (event) {
|
|
var moved = true;
|
|
var offset = {
|
|
x: container.x - Math.round(event.stageX / turtleBlocksScale),
|
|
y: container.y - Math.round(event.stageY / turtleBlocksScale)
|
|
};
|
|
|
|
pressTimer = setTimeout(function () {
|
|
isLong = true;
|
|
if (longImg !== null) {
|
|
container.visible = false;
|
|
container = _makeButton(longImg, '', ox, oy, cellSize, 0);
|
|
}
|
|
}, 500);
|
|
|
|
pressTimerExtra = setTimeout(function () {
|
|
isExtraLong = true;
|
|
if (extraLongImg !== null) {
|
|
container.visible = false;
|
|
container = _makeButton(extraLongImg, '', ox, oy, cellSize, 0);
|
|
}
|
|
}, 1000);
|
|
|
|
var circles = showButtonHighlight(ox, oy, cellSize / 2, event, turtleBlocksScale, stage);
|
|
|
|
container.on('pressup', function (event) {
|
|
hideButtonHighlight(circles, stage);
|
|
container.x = ox;
|
|
container.y = oy;
|
|
|
|
if (longImg !== null || extraLongImg !== null) {
|
|
container.visible = false;
|
|
container = formerContainer;
|
|
container.visible = true;
|
|
}
|
|
|
|
if (action != null && moved && !locked) {
|
|
locked = true;
|
|
|
|
setTimeout(function () {
|
|
locked = false;
|
|
}, 500);
|
|
|
|
clearTimeout(pressTimer);
|
|
clearTimeout(pressTimerExtra);
|
|
|
|
if (!isLong) {
|
|
action();
|
|
} else if (!isExtraLong) {
|
|
longAction();
|
|
} else {
|
|
extraLongAction();
|
|
}
|
|
}
|
|
moved = false;
|
|
});
|
|
|
|
isLong = false;
|
|
isExtraLong = false;
|
|
});
|
|
|
|
};
|
|
};
|
|
});
|