kopia lustrzana https://github.com/backface/turtlestitch
3434 wiersze
106 KiB
JavaScript
3434 wiersze
106 KiB
JavaScript
VERSION="2.8-dev"
|
|
|
|
// get debug mode
|
|
url = new URL(window.location.href);
|
|
searchParams = new URLSearchParams(url.search);
|
|
var DEBUG = (searchParams.get("debug") == "true")
|
|
|
|
// Force flat design
|
|
IDE_Morph.prototype.setDefaultDesign = IDE_Morph.prototype.setFlatDesign;
|
|
|
|
// ad some padding
|
|
IDE_Morph.prototype.originalInit = IDE_Morph.prototype.init;
|
|
IDE_Morph.prototype.init = function(isAutoFill) {
|
|
this.originalInit();
|
|
this.padding = 1;
|
|
/*
|
|
this.droppedText(
|
|
this.getURL(this.resourceURL('stitchcode/embroidery-library.xml')),
|
|
'Embroidery tools'
|
|
);
|
|
*/
|
|
//this.isAnimating = false;
|
|
this.paletteWidth = 250; // initially same as logo width
|
|
//MorphicPreferences.globalFontFamily = 'Sans, Helvetica, Arial';
|
|
this.cloud = new BeetleCloud('/api', this);
|
|
};
|
|
|
|
// change logo
|
|
IDE_Morph.prototype.originalCreateLogo = IDE_Morph.prototype.createLogo;
|
|
IDE_Morph.prototype.createLogo = function () {
|
|
this.originalCreateLogo();
|
|
//if (MorphicPreferences.isFlat) {
|
|
// we are always flat!
|
|
this.logo.texture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAgCAYAAACSEW+lAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wUJDg4Jd5V8gAAACNhJREFUaN7tmXtwVPUVxz/37jOb1yYjyW5IspBNIOQF1KQ+Y8RaxeeM2qpVZuwgdfpQbEWLluKDqbXTmXY6+BjH1qKOAkEsoGMjyCMkEmwSCCYQ8ti8Nwl5sdmwz+ze/fUPZGHLQ9BRSGe///1+v/O7e873nnPuOWchiiiiuIhwHD362FTUW5pKyvb19on/fL4Xv99PQkICIGGxWCiaN1eKEv0toPlQs2hva8Pj8RAfH4csq7j19ttOs2VwcFB02DoYGjpCcXExlhkzLpq98lQkOi8/Tyotu26pwRCDooRoOXwYW3u7OFWmu6tLHGxqIhRS8Hl9SNLF9akpSTRAcnLyy/kFBQwPDaFSq+i390ecH2hoIDY2lrHRUZzj42RaLFI0dXwDbK2oEEeOHEGv15M2fTqpJhOjIyM4nU5kSaK7u5vLi4spLimJEv11YLfbha2tHbVGTUJ8ArJKxuVyMe5wMDAwQEyMAWOSEZ/Xx1333H3R7VRPRZJbW1pFS3Mzs3JzyczMPI3EI4ODorqqigmnk9KysmhN/HUwODgo3i8vF46jR288Z73tcGRtWL9eRBn7mthdWSkONjWdF4FVlZXis+rqS4LsKZWje3t6RFdnF2ULrj8vvfv6+kTFxx9jNCah02mRVSpmz57NrNmzv3O7p1R5Z7PZmJ4+/bzlMzIyJL0+hgmnk7i4eLQaDTV79jA4MCCiRJ8DoyOjZOfkXJA3hkIKBUWFCAROpxODIZaDTQejDcuZ0G+3i701NUKv119YBLTbREgJccWVV3JtaSn5BQUkGhPp7e3BZrN9p159SZd3nR0doru7m6bGJgb6+8m0ZF7gTOQg09PTAdDpdOTl55ORkUF5dw+HmpouTh398yU/E8FgkNjYWLxeL4qi8MRTT/HuO+9QWFTEA4selABWPP2MsGZbWbxkifTiC6tES0sLgclJZufm8utly5bW1daufuvNf2JMTkKtUjHucDB3/nwW/OAGXnv5VX63cgVZVqsEx0eeq557frXb4yEwOYlKpWLVH18kLS1N6rDZREtLCypZRlEUfH4fknRhAehyuSgsKqKuto5DB5uYlpLCvHnzycq2Uldby+7KShGjj2F0bBSz2Xz8d3w+LBYLra2tyLKMXq8nGAzicbtZeOutEkDNnj2i396PTqcjN28OEtDd3U1BYSFms1lqa20TXZ2d5Bfkk56RIUWkDo1Wg9PpZMumTYyMjKDVaVGUIFsrKmhqbAwrv3P7dhr2NwCwZfNmxsfHKbniCjZv2sQTjz++OhQKodVraTxwgE+3bUNWyWg0Ggb6+/lw8yYcDkf4WePj46s/2rKFAbudhIQE4uPjidHrlwKMjY1hMpnIslqxZlspKCzE5/OdN8lVu3eLnFmzCAQCHNi/n9RUE5IkEQgEMBgMFBXNpae7h+HhYZRgEEVR6OrsZHBwEJ/Ph9/nZ2xsDHufHZfLRTCoAFBdVSX21e9Dr9djMBiY9B+Xs7W3oyjHZXw+H329vXjPpm/TF40i05wmqiorw/nr+/O/J577/crw+obSMvHkb54QAFcVl4g/v/SSEEKI51euFEVz8sJyK5Y/LUqvvCq8/vijj8SMtHTRsL9BnDphy7HMFOvefS8iX3Z0dIihI0dOy6Hvl5d/ZV4dHh6u/+TfFWJvTY0A2LC+XJSvW3fGe+vWrhXbPtkaPvtwyxaxfu3a8PrzvXvF22vWCLvdLk6ksnfeelvsq6+PeN6++nrxjzf+Ljo7OgRAe1ubeHvNW6LlcIs448fQ7/cjSRL+ycnIYvvUEaMkABHOe/W1dfztL39l+7btLF6yJCwWDAYR4n/tO93e2LhYXnvlFW658YfiwfvuFwBWq1VKNZlOqy48bg9Hz9IRjo2O/qmutlYc2N9wuWWGhauuvloCSE9Px+v18q+NH5zW6AQnAxE66nS6iKjRaDT4vD40avWJ1h9Zlrm8uDhCN70+BlmWqaut44ONG0VvTy96vQ5Zls78MRQniBDi3D3Ol8dqtZqhoSG2VlTgcBzlpoU3w7Jz90cR70ySUIIK1uxs8vLziI2L473y9We9PdOaRfXuqk/31dej1Wjx+rx4PR58fj8HGhqYlpLCTQtvjiDh6muvkZoaG0V3Vxc1e/ZwuLlZzMnLkwAkWUav1518kR4PKpUqwvFiDAY0Wu1SAEUJRpB3Aj6vl5CiEBOjJyExEVmW8Xq9BAKB8y/vEo1GOjs6wuuhwUFMZlNYsZtvWcgnO7ZLcXHxvPH661+ZO1WqyELH5/Ny2x2389tnnpF+9dhj56yRrysrk4xJRoaHhvH6vMiyjMvl/jLiJIrmnvkvrcKiIuma0tKlCQmJ9PX2hffj4uIIhUInPVqrw2AwhNcxMTFoNGom/f7VACazGZfLRfOh5ghPVGvUaHVaiubO5foFCySTyczExASyLJ/ZoxVF4dixYwSDwfDeXffczR9eWMUvHnlEDNj7aWtt4/Y77+TJ5ctxu91MOCcAKC4pZteOnad4gw+3230yTBUFr9fD8mXLuOuOO0V6RjoetwdJknh19Sssuv8nYnJykhXPrmTuvHlnJbzs+sj2u3LXLuE65orwnlOxccMGERcfT4fNRmxcLGnT005GsAihVp+kQKvVMjIyHMGHWq0OB3hxSYm0ccMG0dT4Bbt27BRqtZqU1BQA3G53+IMZDAaJj4+PmHBEEJ2amsrihx8m02IJ7/3y0UelNW++KXZ8up30jAxWPPssuXPmSAA/vu8+8gsKAHhg0SIMsbFs3blDmEwm6ZprS0lJTaXh4PF6debMmfz04cUgYDIQIDU1lURjIoseegi3y0VQUQgGAuh0ugsq4dLS0mhsbCQpKemM5yazGcdRB37/JDmzZpGbmyudenbZZdPCstNSpqE7JZUkJycTCAQwp5nDd350773SZ9XVIhAIIEnHX47BYCAnJ4fsnGwJwGhMJCvLitFonPqD/5PdX7to/KKRTIuF4pLiS9YeeaoT7fV6MSYZL2mS/y/w+d690eF+FFFEEUUU3wj/Bfcz33x83aRpAAAAAElFTkSuQmCC";
|
|
|
|
this.logo.fixLayout();
|
|
};
|
|
|
|
IDE_Morph.prototype.createPalette = function (forSearching) {
|
|
// assumes that the logo pane has already been created
|
|
// needs the categories pane for layout
|
|
var myself = this;
|
|
|
|
if (this.palette) {
|
|
this.palette.destroy();
|
|
}
|
|
|
|
if (forSearching) {
|
|
this.palette = new ScrollFrameMorph(
|
|
null,
|
|
null,
|
|
this.currentSprite.sliderColor
|
|
);
|
|
|
|
// search toolbar (floating cancel button):
|
|
/* commented out for now
|
|
this.palette.toolBar = new PushButtonMorph(
|
|
this,
|
|
function () {
|
|
myself.refreshPalette();
|
|
myself.palette.adjustScrollBars();
|
|
},
|
|
new SymbolMorph("magnifierOutline", 16)
|
|
);
|
|
this.palette.toolBar.alpha = 0.2;
|
|
this.palette.toolBar.padding = 1;
|
|
// this.palette.toolBar.hint = 'Cancel';
|
|
this.palette.toolBar.labelShadowColor = new Color(140, 140, 140);
|
|
this.palette.toolBar.fixLayout();
|
|
this.palette.toolBar.fixLayout();
|
|
this.palette.add(this.palette.toolBar);
|
|
*/
|
|
} else {
|
|
this.palette = this.currentSprite.palette(this.currentCategory);
|
|
}
|
|
this.palette.isDraggable = false;
|
|
this.palette.acceptsDrops = true;
|
|
this.palette.enableAutoScrolling = false;
|
|
this.palette.contents.acceptsDrops = false;
|
|
|
|
this.palette.reactToDropOf = function (droppedMorph, hand) {
|
|
if (droppedMorph instanceof DialogBoxMorph) {
|
|
myself.world().add(droppedMorph);
|
|
} else if (droppedMorph instanceof SpriteMorph) {
|
|
myself.removeSprite(droppedMorph);
|
|
} else if (droppedMorph instanceof SpriteIconMorph) {
|
|
droppedMorph.destroy();
|
|
myself.removeSprite(droppedMorph.object);
|
|
} else if (droppedMorph instanceof CostumeIconMorph) {
|
|
myself.currentSprite.wearCostume(null);
|
|
droppedMorph.perish();
|
|
} else if (droppedMorph instanceof BlockMorph) {
|
|
myself.stage.threads.stopAllForBlock(droppedMorph);
|
|
if (hand && hand.grabOrigin.origin instanceof ScriptsMorph) {
|
|
hand.grabOrigin.origin.clearDropInfo();
|
|
hand.grabOrigin.origin.lastDroppedBlock = droppedMorph;
|
|
hand.grabOrigin.origin.recordDrop(hand.grabOrigin);
|
|
}
|
|
droppedMorph.perish();
|
|
} else {
|
|
droppedMorph.perish();
|
|
}
|
|
};
|
|
|
|
this.palette.contents.reactToDropOf = function (droppedMorph) {
|
|
// for "undrop" operation
|
|
if (droppedMorph instanceof BlockMorph) {
|
|
droppedMorph.destroy();
|
|
}
|
|
};
|
|
|
|
this.palette.setWidth(this.logo.width());
|
|
this.add(this.palette);
|
|
return this.palette;
|
|
};
|
|
|
|
|
|
|
|
IDE_Morph.prototype.resourceURLOrig = IDE_Morph.prototype.resourceURL;
|
|
IDE_Morph.prototype.resourceURL = function () {
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
if (args[0] == "Backgrounds" || args[0] == "Examples")
|
|
return 'stitchcode/' + args[0] + '/' + args[1];
|
|
else {
|
|
return args.join('/');
|
|
}
|
|
};
|
|
|
|
// Single Sprite mode, no corral and no tabs in the scripting area
|
|
IDE_Morph.prototype.createCorralBar = nop;
|
|
IDE_Morph.prototype.createCorral = nop;
|
|
|
|
// build panes (do not add all)
|
|
IDE_Morph.prototype.buildPanes = function () {
|
|
this.createLogo();
|
|
this.createControlBar();
|
|
this.createCategories();
|
|
this.createPalette();
|
|
this.createSpriteBar();
|
|
this.createSpriteEditor();
|
|
this.createStage();
|
|
//this.createCorralBar();
|
|
//this.createCorral();
|
|
this.createStatusDisplay();
|
|
this.createStageHandle();
|
|
this.createPaletteHandle();
|
|
this.applySavedTurtleStitchSettings();
|
|
|
|
};
|
|
|
|
IDE_Morph.prototype.applySavedTurtleStitchSettings = function () {
|
|
units = this.getSetting('units'),
|
|
hidegrid = this.getSetting('hidegrid');
|
|
hidejumps = this.getSetting('hidejumps');
|
|
hideturtle = this.getSetting('hideturtle');
|
|
hidestitches = this.getSetting('hidestitches');
|
|
warnings = this.getSetting('ignoreWarning');
|
|
isImperial = this.getSetting('isImperial');
|
|
backgroundColor = this.getSetting('backgroundColor')
|
|
defaultPenColor = this.getSetting('defaultPenColor')
|
|
|
|
console.log("apply settings");
|
|
|
|
if(hidegrid) {
|
|
this.stage.scene.grid.toggle();
|
|
//StageMorph.prototype.hideGrid = true;
|
|
}
|
|
else {
|
|
StageMorph.prototype.hideGrid = false;
|
|
}
|
|
|
|
if(hidejumps) {
|
|
//StageMorph.prototype.hideJumps = true;
|
|
this.stage.renderer.toggleJumpLines()
|
|
} else {
|
|
StageMorph.prototype.hideJumps = false;
|
|
}
|
|
|
|
if(hideturtle) {
|
|
this.stage.renderer.toggleTurtle()
|
|
//StageMorph.prototype.hideTurtle = true;
|
|
} else {
|
|
StageMorph.prototype.hideTurtle = false;
|
|
}
|
|
|
|
if(hidestitches) {
|
|
this.stage.renderer.toggleStitchPoints()
|
|
//StageMorph.prototype.hideStitches = true;
|
|
} else {
|
|
StageMorph.prototype.hideStitches = false;
|
|
}
|
|
|
|
if(warnings) {
|
|
this.stage.toggleIgnoreWarnings();
|
|
//StageMorph.prototype.ignoreWarnings = true;
|
|
} else {
|
|
StageMorph.prototype.ignoreWarnings = false;
|
|
}
|
|
|
|
if(isImperial) {
|
|
this.stage.turtleShepherd.toggleMetric();
|
|
this.stage.scene.grid.draw();
|
|
this.stage.renderer.changed = true;
|
|
} else {
|
|
this.stage.turtleShepherd.sMetric = true;
|
|
}
|
|
|
|
if (backgroundColor) {
|
|
this.stage.renderer.setBackgroundColorHex(backgroundColor);
|
|
} else {
|
|
this.stage.renderer.setBackgroundColorHex('#fffffff');
|
|
}
|
|
|
|
if (defaultPenColor) {
|
|
this.stage.renderer.setDefaultPenColorHex(defaultPenColor);
|
|
this.currentSprite.setColor(StageMorph.prototype.defaultPenColor);
|
|
} else {
|
|
this.stage.renderer.setDefaultPenColorHex('#000000');
|
|
}
|
|
|
|
}
|
|
|
|
IDE_Morph.prototype.unitsMenu = function () {
|
|
var menu = new MenuMorph(this),
|
|
world = this.world(),
|
|
pos = this.controlBar.turtlestitchButton.bottomLeft(),
|
|
myself = this;
|
|
|
|
menu.addItem(
|
|
(true ? '\u2713 ' : ' ') + "pixel",
|
|
function () {
|
|
myself.setUnits("pixel");
|
|
}
|
|
);
|
|
menu.addItem(
|
|
(this.units === "millimeter" ? '\u2713 ' : ' ') + "millimeter",
|
|
function () {
|
|
myself.setUnits("millimeter");
|
|
}
|
|
);
|
|
menu.addItem(
|
|
(this.units === "inch" ? '\u2713 ' : ' ') + "inch",
|
|
function () {
|
|
myself.setUnits("inch");
|
|
}
|
|
);
|
|
menu.popup(world, pos);
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.setUnits = function (unit) {
|
|
// TODO:
|
|
}
|
|
|
|
|
|
PaletteHandleMorph.prototype.init = function (target) {
|
|
this.target = target || null;
|
|
HandleMorph.uber.init.call(this);
|
|
this.color = MorphicPreferences.isFlat ?
|
|
new Color(125, 125, 125) : new Color(190, 190, 190);
|
|
this.isDraggable = false;
|
|
this.noticesTransparentClick = true;
|
|
this.setExtent(new Point(12, 50));
|
|
};
|
|
|
|
IDE_Morph.prototype.origNewProject = IDE_Morph.prototype.newProject;
|
|
IDE_Morph.prototype.newProject = function () {
|
|
//this.origNewProject();
|
|
|
|
var project = new Project();
|
|
|
|
project.addDefaultScene();
|
|
|
|
this.source = this.cloud.username ? 'cloud' : null;
|
|
if (location.hash.substr(0, 6) !== '#lang:') {
|
|
location.hash = '';
|
|
}
|
|
this.openProject(project);
|
|
|
|
StageMorph.prototype.dimensions = new Point(480, 360);
|
|
StageMorph.prototype.hiddenPrimitives = {};
|
|
StageMorph.prototype.codeMappings = {};
|
|
StageMorph.prototype.codeHeaders = {};
|
|
StageMorph.prototype.enableCodeMapping = false;
|
|
StageMorph.prototype.enableInheritance = true;
|
|
StageMorph.prototype.enableSublistIDs = false;
|
|
|
|
StageMorph.prototype.hideGrid = false;
|
|
StageMorph.prototype.hideJumps = false;
|
|
StageMorph.prototype.hideTurtle = false;
|
|
StageMorph.prototype.hidestitches = false;
|
|
StageMorph.prototype.ignoreWarnings = false;
|
|
|
|
StageMorph.prototype.backgroundColor = new Color(255,255,255);
|
|
StageMorph.prototype.penColor = new Color(255,255,255);
|
|
|
|
SpriteMorph.prototype.useFlatLineEnds = false;
|
|
|
|
// hide sprite
|
|
this.stage.children[0].hide();
|
|
this.stage.clearAll();
|
|
this.stage.rotateTurtle(this.stage.children[0].heading);
|
|
this.createStatusDisplay();
|
|
// clear stitch cache now (loading projects sends turtle move commands!)
|
|
this.stage.clearAll();
|
|
this.stage.turtleShepherd.clear();
|
|
this.stage.reRender();
|
|
|
|
this.setProjectName('');
|
|
this.projectNotes = '';
|
|
this.createStageHandle();
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.openProject = function (project) {
|
|
if (this.isAddingScenes) {
|
|
project.scenes.itemsArray().forEach(scene => {
|
|
scene.name = this.newSceneName(scene.name, scene);
|
|
this.scenes.add(scene);
|
|
});
|
|
} else {
|
|
this.scenes = project.scenes;
|
|
}
|
|
this.switchToScene(
|
|
project.currentScene || project.scenes.at(1),
|
|
true, // refresh album
|
|
null, // msg
|
|
true // pause generic WHEN hat blocks
|
|
);
|
|
this.createStageHandle();
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.exportProject = function (name) {
|
|
// Export project XML, saving a file to disk
|
|
var menu, str;
|
|
if (name) {
|
|
name = this.setProjectName(name);
|
|
this.scene.captureGlobalSettings();
|
|
try {
|
|
menu = this.showMessage('Exporting');
|
|
project = new Project(this.scenes, this.scene);
|
|
project.name = this.projectName;
|
|
project.notes = this.projectNotes;
|
|
project.origName = this.origName;
|
|
project.origCreator = this.origCreator;
|
|
project.creator = this.creator;
|
|
project.remixHistory = this.remixHistory;
|
|
|
|
str = this.serializer.serialize(
|
|
project
|
|
);
|
|
this.saveXMLAs(str, name);
|
|
menu.destroy();
|
|
this.recordSavedChanges();
|
|
this.showMessage('Exported!', 1);
|
|
} catch (err) {
|
|
if (Process.prototype.isCatchingErrors) {
|
|
this.showMessage('Export failed: ' + err);
|
|
} else {
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.origRawOpenProjectString = IDE_Morph.prototype.rawOpenProjectString;
|
|
IDE_Morph.prototype.rawOpenProjectString = function (str) {
|
|
this.origRawOpenProjectString(str);
|
|
|
|
// hide sprite
|
|
this.stage.children[0].hide();
|
|
this.stage.clearAll();
|
|
this.stage.rotateTurtle(this.stage.children[0].heading);
|
|
this.createStatusDisplay();
|
|
// clear stitch cache now (loading projects sends turtle move commands!)
|
|
this.stage.clearAll();
|
|
this.stage.turtleShepherd.clear();
|
|
this.stage.reRender();
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
TODO: remove sprite instead of hideing it?
|
|
|
|
IDE_Morph.prototype.originalRemoveSprite = IDE_Morph.prototype.removeSprite;
|
|
IDE_Morph.prototype.removeSprite = function (sprite) {
|
|
var stage = sprite.parentThatIsA(StageMorph);
|
|
stage.scene.remove(sprite.beetle);
|
|
stage.reRender();
|
|
this.originalRemoveSprite(sprite);
|
|
};
|
|
|
|
*/
|
|
|
|
// Create contol bar - (and add custom buttons)
|
|
IDE_Morph.prototype.createControlBar = function () {
|
|
// assumes the logo has already been created
|
|
var padding = 4,
|
|
button,
|
|
stopButton,
|
|
pauseButton,
|
|
startButton,
|
|
projectButton,
|
|
settingsButton,
|
|
steppingButton,
|
|
stageSizeButton,
|
|
zoomToFitButton,
|
|
//largeStageSizeButton,
|
|
appModeButton,
|
|
cloudButton,
|
|
upstitchButton,
|
|
x,
|
|
colors = [
|
|
this.groupColor,
|
|
this.frameColor.darker(50),
|
|
this.frameColor.darker(50)
|
|
],
|
|
myself = this;
|
|
|
|
if (this.controlBar) {
|
|
this.controlBar.destroy();
|
|
}
|
|
|
|
this.controlBar = new Morph();
|
|
//this.controlBar.color = this.frameColor;
|
|
this.controlBar.color = new Color(250, 250, 250);
|
|
this.controlBar.setHeight(this.logo.height()); // height is fixed
|
|
this.controlBar.mouseClickLeft = function () {
|
|
this.world().fillPage();
|
|
};
|
|
this.add(this.controlBar);
|
|
|
|
//smallStageButton
|
|
button = new ToggleButtonMorph(
|
|
null, //colors,
|
|
myself, // the IDE is the target
|
|
'toggleStageSize',
|
|
[
|
|
new SymbolMorph('smallStage', 14),
|
|
new SymbolMorph('normalStage', 14)
|
|
],
|
|
function () { // query
|
|
return myself.isSmallStage;
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'stage size\nsmall & normal';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
stageSizeButton = button;
|
|
this.controlBar.add(stageSizeButton);
|
|
this.controlBar.stageSizeButton = button; // for refreshing
|
|
|
|
//appModeButton
|
|
button = new ToggleButtonMorph(
|
|
null, //colors,
|
|
myself, // the IDE is the target
|
|
'toggleAppMode',
|
|
[
|
|
new SymbolMorph('fullScreen', 14),
|
|
new SymbolMorph('normalScreen', 14)
|
|
],
|
|
function () { // query
|
|
return myself.isAppMode;
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'app & edit\nmodes';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
appModeButton = button;
|
|
this.controlBar.add(appModeButton);
|
|
this.controlBar.appModeButton = appModeButton; // for refreshing
|
|
|
|
|
|
|
|
// zoomToFitButton
|
|
//appModeButton
|
|
|
|
button = new ToggleButtonMorph(
|
|
null, //colors,
|
|
this, // the IDE is the target
|
|
'zoomToFit', new SymbolMorph('zoomToFit', 14),
|
|
function () { // query
|
|
return false;
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'start green\nflag scripts';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
zoomToFitButton = button;
|
|
this.controlBar.add(zoomToFitButton);
|
|
this.controlBar.zoomToFitButton = zoomToFitButton; // for refreshing
|
|
|
|
|
|
//steppingButton
|
|
button = new ToggleButtonMorph(
|
|
null, //colors,
|
|
myself, // the IDE is the target
|
|
'toggleSingleStepping',
|
|
[
|
|
new SymbolMorph('footprints', 16),
|
|
new SymbolMorph('footprints', 16)
|
|
],
|
|
function () { // query
|
|
return Process.prototype.enableSingleStepping;
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = new Color(153, 255, 213);
|
|
// button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
button.hint = 'Visible stepping';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
steppingButton = button;
|
|
this.controlBar.add(steppingButton);
|
|
this.controlBar.steppingButton = steppingButton; // for refreshing
|
|
|
|
// stopButton
|
|
button = new ToggleButtonMorph(
|
|
null, // colors
|
|
this, // the IDE is the target
|
|
'stopAllScripts',
|
|
[
|
|
new SymbolMorph('octagon', 14),
|
|
new SymbolMorph('square', 14)
|
|
],
|
|
function () { // query
|
|
return myself.stage ?
|
|
myself.stage.enableCustomHatBlocks &&
|
|
myself.stage.threads.pauseCustomHatBlocks
|
|
: true;
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = new Color(200, 0, 0);
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'stop\nevery-\nthing';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
stopButton = button;
|
|
this.controlBar.add(stopButton);
|
|
this.controlBar.stopButton = stopButton; // for refreshing
|
|
|
|
//pauseButton
|
|
button = new ToggleButtonMorph(
|
|
null, //colors,
|
|
myself, // the IDE is the target
|
|
'togglePauseResume',
|
|
[
|
|
new SymbolMorph('pause', 12),
|
|
new SymbolMorph('pointRight', 14)
|
|
],
|
|
function () { // query
|
|
return myself.isPaused();
|
|
}
|
|
);
|
|
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = new Color(255, 220, 0);
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'pause/resume\nall scripts';
|
|
button.fixLayout();
|
|
button.refresh();
|
|
pauseButton = button;
|
|
this.controlBar.add(pauseButton);
|
|
this.controlBar.pauseButton = pauseButton; // for refreshing
|
|
|
|
// startButton
|
|
button = new PushButtonMorph(
|
|
this,
|
|
'pressStart',
|
|
new SymbolMorph('flag', 14)
|
|
);
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = new Color(0, 200, 0);
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'start green\nflag scripts';
|
|
button.fixLayout();
|
|
startButton = button;
|
|
this.controlBar.add(startButton);
|
|
this.controlBar.startButton = startButton;
|
|
|
|
// steppingSlider
|
|
slider = new SliderMorph(
|
|
61,
|
|
1,
|
|
Process.prototype.flashTime * 100 + 1,
|
|
6,
|
|
'horizontal'
|
|
);
|
|
slider.action = function (num) {
|
|
Process.prototype.flashTime = (num - 1) / 100;
|
|
myself.controlBar.refreshResumeSymbol();
|
|
};
|
|
slider.alpha = MorphicPreferences.isFlat ? 0.1 : 0.3;
|
|
slider.setExtent(new Point(50, 14));
|
|
this.controlBar.add(slider);
|
|
this.controlBar.steppingSlider = slider;
|
|
|
|
// projectButton
|
|
button = new PushButtonMorph(
|
|
this,
|
|
'projectMenu',
|
|
new SymbolMorph('file', 14)
|
|
//'\u270E'
|
|
);
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'open, save, & annotate project';
|
|
button.fixLayout();
|
|
projectButton = button;
|
|
this.controlBar.add(projectButton);
|
|
this.controlBar.projectButton = projectButton; // for menu positioning
|
|
|
|
// settingsButton
|
|
button = new PushButtonMorph(
|
|
this,
|
|
'settingsMenu',
|
|
new SymbolMorph('gears', 14)
|
|
//'\u2699'
|
|
);
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'edit settings';
|
|
button.fixLayout();
|
|
settingsButton = button;
|
|
this.controlBar.add(settingsButton);
|
|
this.controlBar.settingsButton = settingsButton; // for menu positioning
|
|
|
|
// settingsButton
|
|
button = new PushButtonMorph(
|
|
this,
|
|
'turtlestitchMenu',
|
|
new SymbolMorph('turtle', 14)
|
|
//new Morph.fromImageURL('stitchcode/assets/turtles.png')
|
|
//'\u2699'
|
|
);
|
|
button.corner = 12;
|
|
button.color = colors[0];
|
|
button.highlightColor = colors[1];
|
|
button.pressColor = colors[2];
|
|
button.labelMinExtent = new Point(36, 18);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = this.buttonLabelColor;
|
|
button.contrast = this.buttonContrast;
|
|
// button.fixLayout();
|
|
// button.hint = 'edit settings';
|
|
button.fixLayout();
|
|
button.rerender();
|
|
turtlestitchButton = button;
|
|
this.controlBar.add(turtlestitchButton);
|
|
this.controlBar.turtlestitchButton = turtlestitchButton; // for menu positioning
|
|
this.controlBar.fixLayout();
|
|
|
|
this.controlBar.fixLayout = function () {
|
|
x = this.right() - padding;
|
|
[stopButton, pauseButton, startButton].forEach(
|
|
function (button) {
|
|
button.setCenter(myself.controlBar.center());
|
|
button.setRight(x);
|
|
x -= button.width();
|
|
x -= padding;
|
|
}
|
|
);
|
|
|
|
x = Math.min(
|
|
startButton.left() - (3 * padding + 2 * stageSizeButton.width()),
|
|
myself.right() - StageMorph.prototype.dimensions.x *
|
|
(myself.isSmallStage ? myself.stageRatio : 1)
|
|
);
|
|
[stageSizeButton, appModeButton, zoomToFitButton].forEach(
|
|
function (button) {
|
|
x += padding;
|
|
button.setCenter(myself.controlBar.center());
|
|
button.setLeft(x);
|
|
x += button.width();
|
|
}
|
|
);
|
|
|
|
slider.setCenter(myself.controlBar.center());
|
|
slider.setRight(stageSizeButton.left() - padding);
|
|
|
|
steppingButton.setCenter(myself.controlBar.center());
|
|
steppingButton.setRight(slider.left() - padding);
|
|
|
|
settingsButton.setCenter(myself.controlBar.center());
|
|
settingsButton.setLeft(this.left());
|
|
|
|
turtlestitchButton.setCenter(myself.controlBar.center());
|
|
turtlestitchButton.setLeft(settingsButton.right() + padding);
|
|
|
|
projectButton.setCenter(myself.controlBar.center());
|
|
projectButton.setRight(settingsButton.left() - padding);
|
|
|
|
this.refreshSlider();
|
|
this.updateLabel();
|
|
};
|
|
|
|
this.controlBar.refreshSlider = function () {
|
|
if (Process.prototype.enableSingleStepping && !myself.isAppMode) {
|
|
// slider.fixLayout();
|
|
slider.fixLayout();
|
|
slider.show();
|
|
} else {
|
|
slider.hide();
|
|
}
|
|
this.refreshResumeSymbol();
|
|
};
|
|
|
|
this.controlBar.refreshResumeSymbol = function () {
|
|
var pauseSymbols;
|
|
if (Process.prototype.enableSingleStepping &&
|
|
Process.prototype.flashTime > 0.5) {
|
|
myself.stage.threads.pauseAll(myself.stage);
|
|
pauseSymbols = [
|
|
new SymbolMorph('pause', 12),
|
|
new SymbolMorph('stepForward', 14)
|
|
];
|
|
} else {
|
|
pauseSymbols = [
|
|
new SymbolMorph('pause', 12),
|
|
new SymbolMorph('pointRight', 14)
|
|
];
|
|
}
|
|
pauseButton.labelString = pauseSymbols;
|
|
pauseButton.createLabel();
|
|
pauseButton.fixLayout();
|
|
pauseButton.refresh();
|
|
};
|
|
|
|
this.controlBar.updateLabel = function () {
|
|
var suffix = myself.world().isDevMode ?
|
|
' - ' + localize('development mode') : '';
|
|
|
|
if (this.label) {
|
|
this.label.destroy();
|
|
}
|
|
if (myself.isAppMode) {
|
|
return;
|
|
}
|
|
|
|
this.label = new StringMorph(
|
|
(myself.projectName || localize('untitled')) + suffix,
|
|
14,
|
|
'sans-serif',
|
|
true,
|
|
false,
|
|
false,
|
|
MorphicPreferences.isFlat ? null : new Point(2, 1),
|
|
myself.frameColor.darker(myself.buttonContrast)
|
|
);
|
|
this.label.color = myself.buttonLabelColor;
|
|
// this.label.fixLayout();
|
|
this.label.fixLayout();
|
|
this.add(this.label);
|
|
this.label.setCenter(this.center());
|
|
this.label.setLeft(this.turtlestitchButton.right() + padding);
|
|
};
|
|
};
|
|
|
|
IDE_Morph.prototype.turtlestitchMenu = function () {
|
|
var menu,
|
|
stage = this.stage,
|
|
world = this.world(),
|
|
myself = this,
|
|
pos = this.controlBar.settingsButton.bottomLeft(),
|
|
shiftClicked = (world.currentKey === 16);
|
|
|
|
function addPreference(label, toggle, test, onHint, offHint, hide) {
|
|
var on = '\u2611 ',
|
|
off = '\u2610 ';
|
|
if (!hide || shiftClicked) {
|
|
menu.addItem(
|
|
(test ? on : off) + localize(label),
|
|
toggle,
|
|
test ? onHint : offHint,
|
|
hide ? new Color(100, 0, 0) : null
|
|
);
|
|
}
|
|
}
|
|
|
|
menu = new MenuMorph(this);
|
|
|
|
//menu.addItem('Units...', 'unitsMenu');
|
|
//menu.addLine();
|
|
addPreference(
|
|
'Display dimension in Inch',
|
|
function () {
|
|
stage.turtleShepherd.toggleMetric();
|
|
stage.scene.grid.draw();
|
|
stage.renderer.changed = true;
|
|
if (!stage.turtleShepherd.isMetric() ) {
|
|
myself.saveSetting('isImperial', true);
|
|
} else {
|
|
myself.removeSetting('isImperial');
|
|
}
|
|
},
|
|
!stage.turtleShepherd.isMetric() ,
|
|
'uncheck to display dimensions in millimeters',
|
|
'check to show dimensions in inch', );
|
|
|
|
menu.addLine();
|
|
addPreference(
|
|
'Hide grid',
|
|
function () {
|
|
this.stage.scene.grid.toggle();
|
|
if (StageMorph.prototype.hideGrid) {
|
|
myself.saveSetting('hidegrid', true);
|
|
} else {
|
|
myself.removeSetting('hidegrid');
|
|
}
|
|
},
|
|
StageMorph.prototype.hideGrid,
|
|
'uncheck to show grid',
|
|
'check to hide grid',
|
|
);
|
|
|
|
|
|
addPreference(
|
|
'Hide jump stitches',
|
|
function () {
|
|
this.stage.renderer.toggleJumpLines();
|
|
if (StageMorph.prototype.hideJumps) {
|
|
myself.saveSetting('hidejumps', true);
|
|
} else {
|
|
myself.removeSetting('hidejumps');
|
|
}
|
|
},
|
|
StageMorph.prototype.hideJumps ,
|
|
'uncheck to show jump stitches',
|
|
'check to hide jump stitches'
|
|
);
|
|
addPreference(
|
|
'Hide stitch points',
|
|
function () {
|
|
this.stage.renderer.toggleStitchPoints();
|
|
if (StageMorph.prototype.hideStitches) {
|
|
myself.saveSetting('hidestitches', true);
|
|
} else {
|
|
myself.removeSetting('hidestitches');
|
|
}
|
|
},
|
|
StageMorph.prototype.hideStitches,
|
|
'uncheck to show stitch points',
|
|
'check to hide stitch points'
|
|
);
|
|
addPreference(
|
|
'Hide turtle',
|
|
function () {
|
|
this.stage.renderer.toggleTurtle();
|
|
if (StageMorph.prototype.hideTurtle) {
|
|
myself.saveSetting('hideturtle', true);
|
|
} else {
|
|
myself.removeSetting('hideturtle');
|
|
}
|
|
},
|
|
StageMorph.prototype.hideTurtle,
|
|
'uncheck to show turtle',
|
|
'check to hide turtle'
|
|
);
|
|
addPreference(
|
|
'Ignore embroidery warnings',
|
|
function () {
|
|
this.stage.toggleIgnoreWarnings();
|
|
if (StageMorph.prototype.ignoreWarnings ) {
|
|
myself.saveSetting('ignoreWarning', true);
|
|
} else {
|
|
myself.removeSetting('ignoreWarning');
|
|
}
|
|
},
|
|
StageMorph.prototype.ignoreWarnings ,
|
|
|
|
'uncheck to show embroidery specific warnings',
|
|
'check to ignore embroidery specific warnings'
|
|
);
|
|
menu.addLine();
|
|
menu.addItem('Default background color...', 'userSetBackgroundColor');
|
|
menu.addItem('Default pen color...', 'userSetPenColor');
|
|
|
|
menu.addItem('Load a camera snapshot...', 'loadCameraSnapshot');
|
|
menu.addItem('Clear background image', 'clearStageBackground');
|
|
|
|
menu.popup(world, pos);
|
|
};
|
|
|
|
|
|
|
|
|
|
IDE_Morph.prototype.toggleAppMode = function (appMode) {
|
|
var world = this.world(),
|
|
elements = [
|
|
this.logo,
|
|
this.controlBar.projectButton,
|
|
this.controlBar.settingsButton,
|
|
this.controlBar.stageSizeButton,
|
|
this.controlBar.steppingButton,
|
|
this.controlBar.turtlestitchButton,
|
|
//this.controlBar.largeStageSizeButton,
|
|
this.spriteEditor,
|
|
this.paletteHandle,
|
|
this.stageHandle,
|
|
this.palette,
|
|
this.statusDisplay,
|
|
this.categories
|
|
];
|
|
|
|
this.isAppMode = isNil(appMode) ? !this.isAppMode : appMode;
|
|
|
|
if (this.isAppMode) {
|
|
this.wasSingleStepping = Process.prototype.enableSingleStepping;
|
|
if (this.wasSingleStepping) {
|
|
this.toggleSingleStepping();
|
|
}
|
|
this.setColor(this.appModeColor);
|
|
this.controlBar.setColor(this.color);
|
|
this.controlBar.appModeButton.refresh();
|
|
elements.forEach(e =>
|
|
e.hide()
|
|
);
|
|
world.children.forEach(morph => {
|
|
if (morph instanceof DialogBoxMorph) {
|
|
morph.hide();
|
|
}
|
|
});
|
|
if (world.keyboardFocus instanceof ScriptFocusMorph) {
|
|
world.keyboardFocus.stopEditing();
|
|
}
|
|
} else {
|
|
if (this.wasSingleStepping && !Process.prototype.enableSingleStepping) {
|
|
this.toggleSingleStepping();
|
|
}
|
|
this.setColor(this.backgroundColor);
|
|
this.controlBar.setColor(this.frameColor);
|
|
elements.forEach(e =>
|
|
e.show()
|
|
);
|
|
this.stage.setScale(1);
|
|
// show all hidden dialogs
|
|
world.children.forEach(morph => {
|
|
if (morph instanceof DialogBoxMorph) {
|
|
morph.show();
|
|
}
|
|
});
|
|
// prevent scrollbars from showing when morph appears
|
|
world.allChildren().filter(c =>
|
|
c instanceof ScrollFrameMorph
|
|
).forEach(s =>
|
|
s.adjustScrollBars()
|
|
);
|
|
// prevent rotation and draggability controls from
|
|
// showing for the stage
|
|
if (this.currentSprite === this.stage) {
|
|
this.spriteBar.children.forEach(child => {
|
|
if (child instanceof PushButtonMorph) {
|
|
child.hide();
|
|
}
|
|
});
|
|
}
|
|
// update undrop controls
|
|
this.currentSprite.scripts.updateToolbar();
|
|
}
|
|
this.setExtent(this.world().extent());
|
|
};
|
|
|
|
|
|
// IDE_Morph resizing
|
|
IDE_Morph.prototype.setExtent = function (point) {
|
|
var padding = new Point(430, 110),
|
|
minExt,
|
|
ext,
|
|
maxWidth,
|
|
minWidth,
|
|
maxHeight,
|
|
minRatio,
|
|
maxRatio;
|
|
|
|
// determine the minimum dimensions making sense for the current mode
|
|
if (this.isAppMode) {
|
|
if (this.isEmbedMode) {
|
|
minExt = new Point(100, 100);
|
|
} else {
|
|
minExt = StageMorph.prototype.dimensions.add(
|
|
this.controlBar.height() + 10
|
|
);
|
|
}
|
|
} else {
|
|
if (this.stageRatio > 1) {
|
|
minExt = padding.add(StageMorph.prototype.dimensions);
|
|
} else {
|
|
minExt = padding.add(
|
|
StageMorph.prototype.dimensions.multiplyBy(this.stageRatio)
|
|
);
|
|
}
|
|
}
|
|
ext = point.max(minExt);
|
|
|
|
// adjust stage ratio if necessary
|
|
maxWidth = ext.x -
|
|
(200 + this.spriteBar.tabBar.width() + (this.padding * 2));
|
|
minWidth = SpriteIconMorph.prototype.thumbSize.x * 3;
|
|
maxHeight = (ext.y - SpriteIconMorph.prototype.thumbSize.y * 3.5);
|
|
minRatio = minWidth / this.stage.dimensions.x;
|
|
maxRatio = Math.min(
|
|
(maxWidth / this.stage.dimensions.x),
|
|
(maxHeight / this.stage.dimensions.y)
|
|
);
|
|
this.stageRatio = Math.min(maxRatio, Math.max(minRatio, this.stageRatio));
|
|
|
|
// apply
|
|
IDE_Morph.uber.setExtent.call(this, ext);
|
|
this.fixLayout();
|
|
}
|
|
|
|
IDE_Morph.prototype.zoomToFit = function (appMode) {
|
|
this.stage.camera.fitScene();
|
|
}
|
|
|
|
|
|
IDE_Morph.prototype.aboutTurtleStitch = function () {
|
|
var dlg, aboutTxt, pic, world = this.world();
|
|
|
|
aboutTxt = 'TurtleStich! ' + VERSION + '\n\n'
|
|
+ 'Copyright \u24B8 2022 Michael Aschauer\n\n'
|
|
|
|
+ 'TurtleStitch is developed by OSEDA - Association for\n'
|
|
+ 'Development of Open Source Software in Education, Design\n'
|
|
+ 'and Art and stitchcode.com - Visionary Embroidery.\n\n'
|
|
|
|
+ 'The project has been sponsored by netidee Open Innovation\n'
|
|
+ '(Internet Foundation Austria) and kickstarter crowdfunding.\n\n'
|
|
|
|
+ 'TurtleStich is based on Snap!\n\n'
|
|
|
|
dlg = new DialogBoxMorph();
|
|
dlg.inform(localize('About TurtleStitch'), localize(aboutTxt), world, this.logo.cachedTexture);
|
|
|
|
btn1 = dlg.addButton(this.aboutSnap,
|
|
'About Snap!...'
|
|
);
|
|
btn2 = dlg.addButton(
|
|
function () {
|
|
window.open('http://www.turtlestitch.org', 'TurtleStitchWebsite');
|
|
},
|
|
'TurtleStitch Website',
|
|
);
|
|
dlg.fixLayout();
|
|
};
|
|
|
|
// create status display (inspired by beetleblocks)
|
|
IDE_Morph.prototype.createStatusDisplay = function () {
|
|
var frame,
|
|
padding = 1,
|
|
myself = this,
|
|
elements = [],
|
|
stage = this.stage;
|
|
|
|
if (this.statusDisplay) {
|
|
this.statusDisplay.destroy();
|
|
}
|
|
|
|
this.statusDisplay = new Morph();
|
|
this.statusDisplay.color = this.groupColor;
|
|
this.add(this.statusDisplay);
|
|
|
|
frame = new ScrollFrameMorph(null, null, this.sliderColor);
|
|
frame.acceptsDrops = false;
|
|
frame.contents.acceptsDrops = false;
|
|
|
|
frame.alpha = 0;
|
|
|
|
this.statusDisplay.frame = frame;
|
|
this.statusDisplay.add(frame);
|
|
|
|
this.statusDisplay.fixLayout = function () {
|
|
this.setLeft(myself.stage.left());
|
|
this.setTop(myself.stage.bottom() + padding);
|
|
this.setWidth(myself.stage.width());
|
|
this.setHeight(myself.height() - myself.stage.height() - myself.controlBar.height() - padding);
|
|
this.frame.setExtent(this.extent());
|
|
this.arrangeContents();
|
|
this.refresh();
|
|
};
|
|
|
|
this.statusDisplay.arrangeContents = function () {
|
|
var x = this.left() + padding,
|
|
y = this.top() + padding,
|
|
max = this.right() - padding,
|
|
start = x,
|
|
middle = (max - start) / 2 + start;
|
|
|
|
this.frame.contents.children.forEach(function (element) {
|
|
element.setPosition(new Point(x, y));
|
|
x += element.width();
|
|
|
|
if (element instanceof ToggleMorph)
|
|
{ x+= element.label.width() + 2; }
|
|
|
|
if (element.newLines) {
|
|
y += 14 * element.newLines;
|
|
x = start;
|
|
}
|
|
|
|
if (element.newColumn) {
|
|
if (element.columns) {
|
|
x = ((max - start) / element.columns) * element.newColumn + start;
|
|
} else {
|
|
x = middle;
|
|
}
|
|
}
|
|
});
|
|
|
|
this.frame.contents.adjustBounds();
|
|
};
|
|
|
|
this.statusDisplay.addElement = function (element) {
|
|
|
|
if (typeof element == 'string') {
|
|
if (element == '-') {
|
|
element = new Morph();
|
|
element.setHeight(1);
|
|
element.setWidth(this.width());
|
|
element.setColor(new Color(200, 200, 200));
|
|
element.newLines = 0.5;
|
|
element.flush = true;
|
|
} else {
|
|
element = new StringMorph(localize(element), 12, null, true);
|
|
}
|
|
if (element.hidden) {
|
|
element.setColor(new Color(0,0,0,0));
|
|
}
|
|
};
|
|
|
|
this.frame.contents.add(element);
|
|
this.fixLayout();
|
|
};
|
|
|
|
this.statusDisplay.refresh = function () {
|
|
this.frame.contents.children.forEach(function (element) {
|
|
if (element.hasOwnProperty('update')) {
|
|
element.update();
|
|
element.changed();
|
|
// element.fixLayout();
|
|
element.fixLayout();
|
|
element.changed();
|
|
};
|
|
});
|
|
};
|
|
|
|
this.statusDisplay.acceptsDrops = function () {
|
|
return false;
|
|
};
|
|
|
|
this.statusDisplay.watchers = function (leftPos) {
|
|
/* answer an array of all currently visible watchers.
|
|
If leftPos is specified, filter the list for all
|
|
shown or hidden watchers whose left side equals
|
|
the given border (for automatic positioning) */
|
|
|
|
return this.children.filter(function (morph) {
|
|
if (morph instanceof WatcherMorph) {
|
|
if (leftPos) {
|
|
return morph.left() === leftPos;
|
|
}
|
|
return morph.isVisible;
|
|
}
|
|
return false;
|
|
});
|
|
};
|
|
|
|
this.statusDisplay.step = function() {
|
|
// update watchers
|
|
current = Date.now();
|
|
elapsed = current - this.lastWatcherUpdate;
|
|
leftover = (1000 / this.watcherUpdateFrequency) - elapsed;
|
|
if (leftover < 1) {
|
|
this.watchers().forEach(function (w) {
|
|
w.update();
|
|
});
|
|
this.lastWatcherUpdate = Date.now();
|
|
}
|
|
};
|
|
|
|
this.statusDisplay.lastWatcherUpdate = Date.now();
|
|
this.statusDisplay.watcherUpdateFrequency = 250;
|
|
|
|
var space = new Morph();
|
|
space.alpha = 0;
|
|
space.newLines = 0.5;
|
|
elements.push(space);
|
|
|
|
elements.push(' Stitches : ');
|
|
element = new StringMorph();
|
|
element.update = function () {
|
|
this.text = (stage.turtleShepherd.getStepCount()).toString()+ " ";
|
|
};
|
|
element.columns = 3;
|
|
element.newColumn = 1;
|
|
elements.push(element);
|
|
|
|
|
|
elements.push('Jumps : ');
|
|
element = new StringMorph();
|
|
element.update = function () {
|
|
this.text = (stage.turtleShepherd.getJumpCount()).toString()+ " ";
|
|
};
|
|
element.columns = 3;
|
|
element.newColumn = 2;
|
|
elements.push(element);
|
|
|
|
elements.push('Size : ');
|
|
element = new StringMorph();
|
|
element.update = function () {
|
|
this.text = (stage.turtleShepherd.getDimensions());
|
|
};
|
|
element.newLines = 1;
|
|
elements.push(element);
|
|
element.newLines = 1;
|
|
elements.push('-');
|
|
|
|
// too long
|
|
elements.push(' ');
|
|
element = new StringMorph();
|
|
element.color = new Color(255, 0, 0);
|
|
element.update = function () {
|
|
this.text = "" + (stage.turtleShepherd.getTooLongStr());
|
|
};
|
|
element.columns = 2;
|
|
element.newColumn = 1;
|
|
elements.push(element);
|
|
|
|
// density warning
|
|
elements.push('');
|
|
element = new StringMorph();
|
|
element.color = new Color(255, 0, 0);
|
|
element.update = function () {
|
|
this.text = "" + (stage.turtleShepherd.getDensityWarningStr());
|
|
};
|
|
element.columns = 2;
|
|
element.newColumn = 2;
|
|
elements.push(element);
|
|
|
|
// density warning
|
|
elements.push('');
|
|
element = new StringMorph("");
|
|
element.newLines = 2;
|
|
elements.push(element);
|
|
|
|
|
|
var zoomInButton = new PushButtonMorph(
|
|
null,
|
|
function () {
|
|
stage.camera.zoomOut();
|
|
stage.renderer.changed = true; },
|
|
'+'
|
|
);
|
|
elements.push(zoomInButton);
|
|
|
|
var zoomOutButton = new PushButtonMorph(
|
|
null,
|
|
function () {
|
|
stage.camera.zoomIn();
|
|
stage.renderer.changed = true;
|
|
},
|
|
' - '
|
|
);
|
|
elements.push(zoomOutButton);
|
|
|
|
var resetCameraButton = new PushButtonMorph(
|
|
null,
|
|
function () { stage.camera.reset(); },
|
|
'Reset View'
|
|
);
|
|
elements.push(resetCameraButton);
|
|
resetCameraButton.columns = 4;
|
|
resetCameraButton.newColumn = 2;
|
|
|
|
|
|
var XRayButton = new ToggleMorph(
|
|
'checkbox',
|
|
null,
|
|
function () {
|
|
if (stage.isXRay) {
|
|
myself.showMessage("turn off X-RAY ...");
|
|
window.setTimeout(
|
|
function() {
|
|
stage.turnXRayOff();
|
|
myself.showMessage("ok.",0.4);
|
|
myself.XRayButton.refresh();
|
|
}, 250);
|
|
} else {
|
|
myself.showMessage("rendering X-RAY ...");
|
|
window.setTimeout(
|
|
function() {
|
|
stage.turnXRayOn();
|
|
myself.showMessage("ok.", 0.4);
|
|
myself.XRayButton.refresh();
|
|
} ,250);
|
|
}
|
|
},
|
|
'X-Ray',
|
|
function () {
|
|
return stage.getIsXRay();
|
|
});
|
|
elements.push(XRayButton);
|
|
myself.XRayButton = XRayButton;
|
|
XRayButton.columns = 4;
|
|
XRayButton.newColumn = 3;
|
|
|
|
|
|
var toggleTurboButton = new ToggleMorph(
|
|
'checkbox',
|
|
null,
|
|
function () {
|
|
myself.toggleFastTracking();
|
|
},
|
|
'Turbo mode',
|
|
function () {
|
|
return stage.isFastTracked;
|
|
});
|
|
toggleTurboButton.newLines = 2;
|
|
elements.push(toggleTurboButton);
|
|
|
|
|
|
var fitScreenButton = new PushButtonMorph(
|
|
null,
|
|
function () { stage.camera.fitScene(); },
|
|
'Zoom to fit'
|
|
);
|
|
elements.push(fitScreenButton);
|
|
fitScreenButton.newLines = 3;
|
|
|
|
elements.push('-');
|
|
|
|
|
|
var downloadSVGButton = new PushButtonMorph(
|
|
null,
|
|
function () { myself.downloadSVG(); },
|
|
'Export as SVG'
|
|
);
|
|
downloadSVGButton.columns = 6;
|
|
downloadSVGButton.newColumn = 2;
|
|
elements.push(downloadSVGButton);
|
|
|
|
var ignoreColorsButton = new ToggleMorph(
|
|
'checkbox',
|
|
null,
|
|
function () {
|
|
stage.turtleShepherd.toggleIgnoreColors();
|
|
},
|
|
'Ignore colors during export',
|
|
function () {
|
|
return stage.turtleShepherd.getIgnoreColors();
|
|
});
|
|
|
|
ignoreColorsButton.newLines = 1.7;
|
|
elements.push(ignoreColorsButton);
|
|
|
|
/* hide for now
|
|
var downloadDXFButton = new PushButtonMorph(
|
|
null,
|
|
function () { myself.downloadDXF(); },
|
|
'Export as DXF'
|
|
);
|
|
downloadDXFButton.newLines = 1.7;
|
|
elements.push(downloadDXFButton);
|
|
*/
|
|
|
|
var downloadEXPButton = new PushButtonMorph(
|
|
null,
|
|
function () { myself.downloadEXP(); },
|
|
'Export as Melco/EXP'
|
|
);
|
|
downloadEXPButton.newLines = 1.7;
|
|
elements.push(downloadEXPButton);
|
|
|
|
var downloadDSTButton = new PushButtonMorph(
|
|
null,
|
|
function () { myself.downloadDST(); },
|
|
'Export as Tajima/DST'
|
|
);
|
|
downloadDSTButton.newLines = 2.7;
|
|
elements.push(downloadDSTButton);
|
|
|
|
if (DEBUG) {
|
|
elements.push(' DEBUG MODE: true');
|
|
element = new StringMorph("");
|
|
|
|
element.newLines = 1.2;
|
|
elements.push(element);
|
|
elements.push(' RENDERER: ');
|
|
element = new StringMorph();
|
|
element.update = function () {
|
|
this.text = stage.renderer_status_msg;
|
|
};
|
|
element.newLines = 1;
|
|
elements.push(element);
|
|
elements.push(' ');
|
|
}
|
|
|
|
elements.forEach(function(each) { myself.statusDisplay.addElement(each); });
|
|
};
|
|
|
|
// fix layout custom function
|
|
IDE_Morph.prototype.fixLayout = function (situation) {
|
|
// situation is a string, i.e.
|
|
// 'selectSprite' or 'refreshPalette' or 'tabEditor'
|
|
var padding = this.padding,
|
|
maxPaletteWidth;
|
|
|
|
Morph.prototype.trackChanges = false;
|
|
|
|
if (situation !== 'refreshPalette') {
|
|
// controlBar
|
|
this.controlBar.setPosition(this.logo.topRight());
|
|
this.controlBar.setWidth(this.right() - this.controlBar.left());
|
|
this.controlBar.fixLayout();
|
|
|
|
// categories
|
|
this.categories.setLeft(this.logo.left());
|
|
this.categories.setTop(this.logo.bottom()+1);
|
|
this.categories.setWidth(this.paletteWidth);
|
|
}
|
|
|
|
// palette
|
|
this.palette.setLeft(this.logo.left());
|
|
this.palette.setTop(this.categories.bottom());
|
|
this.palette.setHeight(this.bottom() - this.palette.top());
|
|
this.palette.setWidth(this.paletteWidth);
|
|
|
|
if (situation !== 'refreshPalette') {
|
|
// stage
|
|
if (this.isAppMode) {
|
|
this.stage.setScale(Math.floor(Math.min(
|
|
(this.width() - padding * 2) / this.stage.dimensions.x,
|
|
(this.height() - this.controlBar.height() * 2 - padding * 2)
|
|
/ this.stage.dimensions.y
|
|
) * 10) / 10);
|
|
this.stage.setCenter(this.center());
|
|
} else {
|
|
this.stage.setScale(this.isSmallStage ? this.stageRatio : 1);
|
|
this.stage.setTop(this.logo.bottom() + padding);
|
|
this.stage.setRight(this.right());
|
|
maxPaletteWidth = this.width() -
|
|
this.stage.width() -
|
|
this.spriteBar.tabBar.width() -
|
|
(this.padding * 2);
|
|
if (this.paletteWidth > maxPaletteWidth) {
|
|
this.paletteWidth = maxPaletteWidth;
|
|
this.fixLayout();
|
|
}
|
|
this.stageHandle.fixLayout();
|
|
this.paletteHandle.fixLayout();
|
|
}
|
|
|
|
if (this.spriteEditor.isVisible) {
|
|
this.spriteEditor.setLeft(this.paletteWidth + padding);
|
|
this.spriteEditor.setTop(this.logo.bottom() + padding);
|
|
this.spriteEditor.setExtent(new Point(
|
|
//this.spriteBar.width(),
|
|
Math.max(0, this.stage.left() - padding - this.spriteEditor.left()),
|
|
this.bottom() - this.spriteEditor.top()
|
|
));
|
|
}
|
|
this.statusDisplay.fixLayout();
|
|
|
|
}
|
|
|
|
Morph.prototype.trackChanges = true;
|
|
this.changed();
|
|
};
|
|
|
|
// SVG export
|
|
IDE_Morph.prototype.downloadSVG = function() {
|
|
svgStr = this.stage.turtleShepherd.toSVG();
|
|
blob = new Blob([svgStr], {type: 'text/plain;charset=utf-8'});
|
|
saveAs(blob, (this.projectName ? this.projectName : 'turtlestitch') + '.svg');
|
|
};
|
|
|
|
// DXF export
|
|
IDE_Morph.prototype.downloadDXF = function() {
|
|
dxfStr = this.stage.turtleShepherd.toDXF();
|
|
blob = new Blob([dxfStr]);
|
|
saveAs(blob, (this.projectName ? this.projectName : 'turtlestitch') + '.dxf');
|
|
};
|
|
|
|
// EXP export
|
|
IDE_Morph.prototype.downloadEXP = function() {
|
|
expUintArr = this.stage.turtleShepherd.toEXP();
|
|
blob = new Blob([expUintArr], {type: 'application/octet-stream'});
|
|
saveAs(blob, (this.projectName ? this.projectName : 'turtlestitch') + '.exp');
|
|
};
|
|
|
|
// DST export
|
|
IDE_Morph.prototype.downloadDST = function() {
|
|
var name = this.projectName ? this.projectName : 'turtlestitch';
|
|
expUintArr = this.stage.turtleShepherd.toDST(name);
|
|
blob = new Blob([expUintArr], {type: 'application/octet-stream'});
|
|
saveAs(blob, name + '.dst');
|
|
};
|
|
|
|
// PNG export
|
|
IDE_Morph.prototype.downloadPNG = function() {
|
|
var name = this.projectName ? this.projectName : 'turtlestitch';
|
|
|
|
dataURL = this.stage.turtleShepherd.toPNG(name);
|
|
var binary = atob( dataURL.substr( dataURL.indexOf(',') + 1 ) ),
|
|
i = binary.length,
|
|
view = new Uint8Array(i);
|
|
|
|
while (i--) {
|
|
view[i] = binary.charCodeAt(i);
|
|
}
|
|
|
|
blob = new Blob([view], {type: 'image/png'});
|
|
saveAs(blob, name + '.png');
|
|
};
|
|
|
|
|
|
/*
|
|
IDE_Morph.prototype.setProjectName = function (string) {
|
|
if (string.replace(/['"]/g, '') != this.projectName || SnapCloud.username != this.creator) {
|
|
this.remixHistory = this.creator + ":" + this.projectName + ";" + this.remixHistory
|
|
this.origName = this.projectName;
|
|
}
|
|
this.origName = this.projectName;
|
|
this.origCreator = SnapCloud.username != this.creator ? this.creator : SnapCloud.username;
|
|
this.creator = SnapCloud.username ? SnapCloud.username : "anonymous";
|
|
this.projectName = string.replace(/['"]/g, ''); // filter quotation marks
|
|
this.hasChangedMedia = true;
|
|
this.controlBar.updateLabel();
|
|
};
|
|
*/
|
|
|
|
IDE_Morph.prototype.setProjectName = function (string) {
|
|
var projectScene = this.scenes.at(1),
|
|
name = this.newSceneName(string, projectScene);
|
|
if (name !== projectScene.name) {
|
|
projectScene.name = name;
|
|
projectScene.stage.version = Date.now();
|
|
this.recordUnsavedChanges();
|
|
if (projectScene === this.scene) {
|
|
this.controlBar.updateLabel();
|
|
}
|
|
}
|
|
|
|
if (string.replace(/['"]/g, '') != this.projectName || SnapCloud.username != this.creator) {
|
|
this.remixHistory = this.creator + ":" + this.projectName + ";" + this.remixHistory
|
|
this.origName = this.projectName;
|
|
}
|
|
this.origName = this.projectName;
|
|
this.origCreator = SnapCloud.username != this.creator ? this.creator : SnapCloud.username;
|
|
this.creator = SnapCloud.username ? SnapCloud.username : "anonymous";
|
|
this.projectName = string.replace(/['"]/g, '');
|
|
|
|
this.controlBar.updateLabel();
|
|
|
|
return name;
|
|
};
|
|
|
|
|
|
|
|
|
|
IDE_Morph.prototype.createSpriteBar = function () {
|
|
// assumes that the categories pane has already been created
|
|
var rotationStyleButtons = [],
|
|
thumbSize = new Point(45, 45),
|
|
nameField,
|
|
padlock,
|
|
thumbnail,
|
|
tabCorner = 15,
|
|
tabColors = this.tabColors,
|
|
tabBar = new AlignmentMorph('row', -tabCorner * 2),
|
|
tab,
|
|
symbols = ['\u2192', '\u21BB', '\u2194'],
|
|
labels = ['don\'t rotate', 'can rotate', 'only face left/right'],
|
|
myself = this;
|
|
|
|
if (this.spriteBar) {
|
|
this.spriteBar.destroy();
|
|
}
|
|
|
|
this.spriteBar = new Morph();
|
|
this.spriteBar.color = this.frameColor;
|
|
//this.add(this.spriteBar);
|
|
|
|
function addRotationStyleButton(rotationStyle) {
|
|
var colors = myself.rotationStyleColors,
|
|
button;
|
|
|
|
button = new ToggleButtonMorph(
|
|
colors,
|
|
myself, // the IDE is the target
|
|
function () {
|
|
if (myself.currentSprite instanceof SpriteMorph) {
|
|
myself.currentSprite.rotationStyle = rotationStyle;
|
|
myself.currentSprite.changed();
|
|
myself.currentSprite.fixLayout();
|
|
myself.currentSprite.changed();
|
|
}
|
|
rotationStyleButtons.forEach(function (each) {
|
|
each.refresh();
|
|
});
|
|
},
|
|
symbols[rotationStyle], // label
|
|
function () { // query
|
|
return myself.currentSprite instanceof SpriteMorph
|
|
&& myself.currentSprite.rotationStyle === rotationStyle;
|
|
},
|
|
null, // environment
|
|
localize(labels[rotationStyle])
|
|
);
|
|
|
|
button.corner = 8;
|
|
button.labelMinExtent = new Point(11, 11);
|
|
button.padding = 0;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = myself.buttonLabelColor;
|
|
button.fixLayout();
|
|
button.refresh();
|
|
rotationStyleButtons.push(button);
|
|
button.setPosition(myself.spriteBar.position().add(2));
|
|
button.setTop(button.top()
|
|
+ ((rotationStyleButtons.length - 1) * (button.height() + 2))
|
|
);
|
|
myself.spriteBar.add(button);
|
|
if (myself.currentSprite instanceof StageMorph) {
|
|
button.hide();
|
|
}
|
|
return button;
|
|
}
|
|
|
|
addRotationStyleButton(1);
|
|
addRotationStyleButton(2);
|
|
addRotationStyleButton(0);
|
|
this.rotationStyleButtons = rotationStyleButtons;
|
|
|
|
thumbnail = new Morph();
|
|
thumbnail.setExtent(thumbSize);
|
|
thumbnail.image = this.currentSprite.thumbnail(thumbSize);
|
|
thumbnail.setPosition(
|
|
rotationStyleButtons[0].topRight().add(new Point(5, 3))
|
|
);
|
|
this.spriteBar.add(thumbnail);
|
|
|
|
thumbnail.fps = 3;
|
|
|
|
thumbnail.step = function () {
|
|
if (thumbnail.version !== myself.currentSprite.version) {
|
|
thumbnail.image = myself.currentSprite.thumbnail(thumbSize);
|
|
thumbnail.changed();
|
|
thumbnail.version = myself.currentSprite.version;
|
|
}
|
|
};
|
|
|
|
nameField = new InputFieldMorph(this.currentSprite.name);
|
|
nameField.setWidth(100); // fixed dimensions
|
|
nameField.contrast = 90;
|
|
nameField.setPosition(thumbnail.topRight().add(new Point(10, 3)));
|
|
this.spriteBar.add(nameField);
|
|
nameField.fixLayout();
|
|
nameField.accept = function () {
|
|
var newName = nameField.getValue();
|
|
myself.currentSprite.setName(
|
|
myself.newSpriteName(newName, myself.currentSprite)
|
|
);
|
|
nameField.setContents(myself.currentSprite.name);
|
|
};
|
|
this.spriteBar.reactToEdit = nameField.accept;
|
|
|
|
// padlock
|
|
padlock = new ToggleMorph(
|
|
'checkbox',
|
|
null,
|
|
function () {
|
|
myself.currentSprite.isDraggable =
|
|
!myself.currentSprite.isDraggable;
|
|
},
|
|
localize('draggable'),
|
|
function () {
|
|
return myself.currentSprite.isDraggable;
|
|
}
|
|
);
|
|
padlock.label.isBold = false;
|
|
padlock.label.setColor(this.buttonLabelColor);
|
|
padlock.color = tabColors[2];
|
|
padlock.highlightColor = tabColors[0];
|
|
padlock.pressColor = tabColors[1];
|
|
|
|
padlock.tick.shadowOffset = MorphicPreferences.isFlat ?
|
|
new Point() : new Point(-1, -1);
|
|
padlock.tick.shadowColor = new Color(); // black
|
|
padlock.tick.color = this.buttonLabelColor;
|
|
padlock.tick.isBold = false;
|
|
padlock.tick.fixLayout();
|
|
|
|
padlock.setPosition(nameField.bottomLeft().add(2));
|
|
padlock.fixLayout();
|
|
this.spriteBar.add(padlock);
|
|
if (this.currentSprite instanceof StageMorph) {
|
|
padlock.hide();
|
|
}
|
|
|
|
// tab bar
|
|
tabBar.tabTo = function (tabString) {
|
|
var active;
|
|
myself.currentTab = tabString;
|
|
this.children.forEach(function (each) {
|
|
each.refresh();
|
|
if (each.state) {active = each; }
|
|
});
|
|
active.refresh(); // needed when programmatically tabbing
|
|
myself.createSpriteEditor();
|
|
myself.fixLayout('tabEditor');
|
|
};
|
|
|
|
tab = new TabMorph(
|
|
tabColors,
|
|
null, // target
|
|
function () {tabBar.tabTo('scripts'); },
|
|
localize('Scripts'), // label
|
|
function () { // query
|
|
return myself.currentTab === 'scripts';
|
|
}
|
|
);
|
|
tab.padding = 3;
|
|
tab.corner = tabCorner;
|
|
tab.edge = 1;
|
|
tab.labelShadowOffset = new Point(-1, -1);
|
|
tab.labelShadowColor = tabColors[1];
|
|
tab.labelColor = this.buttonLabelColor;
|
|
tab.fixLayout();
|
|
tab.fixLayout();
|
|
tabBar.add(tab);
|
|
|
|
tab = new TabMorph(
|
|
tabColors,
|
|
null, // target
|
|
function () {tabBar.tabTo('costumes'); },
|
|
localize('Costumes'), // label
|
|
function () { // query
|
|
return myself.currentTab === 'costumes';
|
|
}
|
|
);
|
|
tab.padding = 3;
|
|
tab.corner = tabCorner;
|
|
tab.edge = 1;
|
|
tab.labelShadowOffset = new Point(-1, -1);
|
|
tab.labelShadowColor = tabColors[1];
|
|
tab.labelColor = this.buttonLabelColor;
|
|
tab.fixLayout();
|
|
tab.fixLayout();
|
|
tabBar.add(tab);
|
|
|
|
tab = new TabMorph(
|
|
tabColors,
|
|
null, // target
|
|
function () {tabBar.tabTo('sounds'); },
|
|
localize('Sounds'), // label
|
|
function () { // query
|
|
return myself.currentTab === 'sounds';
|
|
}
|
|
);
|
|
tab.padding = 3;
|
|
tab.corner = tabCorner;
|
|
tab.edge = 1;
|
|
tab.labelShadowOffset = new Point(-1, -1);
|
|
tab.labelShadowColor = tabColors[1];
|
|
tab.labelColor = this.buttonLabelColor;
|
|
tab.fixLayout();
|
|
tab.fixLayout();
|
|
tabBar.add(tab);
|
|
|
|
tabBar.fixLayout();
|
|
tabBar.children.forEach(function (each) {
|
|
each.refresh();
|
|
});
|
|
this.spriteBar.tabBar = tabBar;
|
|
this.spriteBar.add(this.spriteBar.tabBar);
|
|
|
|
this.spriteBar.fixLayout = function () {
|
|
this.tabBar.setLeft(this.left());
|
|
this.tabBar.setBottom(this.bottom());
|
|
};
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.createCategories = function () {
|
|
var myself = this,
|
|
categorySelectionAction = this.scene.unifiedPalette ? scrollToCategory
|
|
: changePalette,
|
|
categoryQueryAction = this.scene.unifiedPalette ? queryTopCategory
|
|
: queryCurrentCategory;
|
|
|
|
if (this.categories) {
|
|
this.categories.destroy();
|
|
}
|
|
this.categories = new Morph();
|
|
this.categories.color = this.groupColor;
|
|
this.categories.bounds.setWidth(this.paletteWidth);
|
|
this.categories.buttons = [];
|
|
|
|
this.categories.refresh = function () {
|
|
this.buttons.forEach(cat => {
|
|
cat.refresh();
|
|
if (cat.state) {
|
|
cat.scrollIntoView();
|
|
}
|
|
});
|
|
};
|
|
|
|
this.categories.refreshEmpty = function () {
|
|
var dict = myself.currentSprite.emptyCategories();
|
|
dict.variables = dict.variables || dict.lists || dict.other;
|
|
this.buttons.forEach(cat => {
|
|
if (dict[cat.category]) {
|
|
cat.enable();
|
|
} else {
|
|
cat.disable();
|
|
}
|
|
});
|
|
};
|
|
|
|
function changePalette(category) {
|
|
return () => {
|
|
myself.currentCategory = category;
|
|
myself.categories.buttons.forEach(each =>
|
|
each.refresh()
|
|
);
|
|
myself.refreshPalette(true);
|
|
};
|
|
}
|
|
|
|
function scrollToCategory(category) {
|
|
return () => myself.scrollPaletteToCategory(category);
|
|
}
|
|
|
|
function queryCurrentCategory(category) {
|
|
return () => myself.currentCategory === category;
|
|
}
|
|
|
|
function queryTopCategory(category) {
|
|
return () => myself.topVisibleCategoryInPalette() === category;
|
|
}
|
|
|
|
function addCategoryButton(category) {
|
|
var labelWidth = 75,
|
|
colors = [
|
|
myself.frameColor,
|
|
myself.frameColor.darker(MorphicPreferences.isFlat ? 5 : 50),
|
|
SpriteMorph.prototype.blockColor[category]
|
|
],
|
|
button;
|
|
|
|
button = new ToggleButtonMorph(
|
|
colors,
|
|
myself, // the IDE is the target
|
|
categorySelectionAction(category),
|
|
category[0].toUpperCase().concat(category.slice(1)), // label
|
|
categoryQueryAction(category), // query
|
|
null, // env
|
|
null, // hint
|
|
labelWidth, // minWidth
|
|
true // has preview
|
|
);
|
|
|
|
button.category = category;
|
|
button.corner = 8;
|
|
button.padding = 2;
|
|
button.labelShadowOffset = new Point(0,0);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = myself.buttonLabelColor;
|
|
if (MorphicPreferences.isFlat) {
|
|
button.labelPressColor = WHITE;
|
|
}
|
|
button.fixLayout();
|
|
button.refresh();
|
|
myself.categories.add(button);
|
|
myself.categories.buttons.push(button);
|
|
return button;
|
|
}
|
|
|
|
function addCustomCategoryButton(category, color) {
|
|
var labelWidth = 168,
|
|
colors = [
|
|
myself.frameColor,
|
|
myself.frameColor.darker(MorphicPreferences.isFlat ? 5 : 50),
|
|
color
|
|
],
|
|
button;
|
|
|
|
button = new ToggleButtonMorph(
|
|
colors,
|
|
myself, // the IDE is the target
|
|
categorySelectionAction(category),
|
|
category, // label
|
|
categoryQueryAction(category), // query
|
|
null, // env
|
|
null, // hint
|
|
labelWidth, // minWidth
|
|
true // has preview
|
|
);
|
|
|
|
button.category = category;
|
|
button.corner = 8;
|
|
button.padding = 2;
|
|
button.labelShadowOffset = new Point(-1, -1);
|
|
button.labelShadowColor = colors[1];
|
|
button.labelColor = myself.buttonLabelColor;
|
|
if (MorphicPreferences.isFlat) {
|
|
button.labelPressColor = WHITE;
|
|
}
|
|
button.fixLayout();
|
|
button.refresh();
|
|
myself.categories.add(button);
|
|
myself.categories.buttons.push(button);
|
|
return button;
|
|
}
|
|
|
|
function fixCategoriesLayout() {
|
|
var buttonWidth = myself.categories.children[0].width(),
|
|
buttonHeight = myself.categories.children[0].height(),
|
|
more = SpriteMorph.prototype.customCategories.size,
|
|
border = 10,
|
|
xPadding = 5,
|
|
yPadding = 3,
|
|
l = myself.categories.left(),
|
|
t = myself.categories.top(),
|
|
scroller,
|
|
row,
|
|
col,
|
|
i;
|
|
|
|
myself.categories.children.forEach((button, i) => {
|
|
row = i < 8 ? i % 4 : i - 4;
|
|
col = (i < 4 || i > 7) ? 1 : 2;
|
|
button.setPosition(new Point(
|
|
l + (col * xPadding + ((col - 1) * buttonWidth)),
|
|
t + ((row + 1) * yPadding + (row * buttonHeight) + border) +
|
|
(i > 9 ?0 : 0)
|
|
));
|
|
});
|
|
|
|
if (more > 6) {
|
|
scroller = new ScrollFrameMorph(null, null, myself.sliderColor);
|
|
scroller.setColor(myself.groupColor);
|
|
scroller.acceptsDrops = false;
|
|
scroller.contents.acceptsDrops = false;
|
|
scroller.setPosition(
|
|
new Point(0, myself.categories.children[8].top())
|
|
);
|
|
scroller.setWidth(myself.paletteWidth);
|
|
scroller.setHeight(buttonHeight * 6 + yPadding * 5);
|
|
|
|
for (i = 0; i < more; i += 1) {
|
|
scroller.addContents(myself.categories.children[8]);
|
|
}
|
|
myself.categories.add(scroller);
|
|
myself.categories.scroller = scroller;
|
|
myself.categories.setHeight(
|
|
(4 + 1) * yPadding
|
|
+ 4 * buttonHeight
|
|
+ 6 * (yPadding + buttonHeight) + border + 2
|
|
+ 2 * border
|
|
);
|
|
} else {
|
|
myself.categories.setHeight(
|
|
(4 + 1) * yPadding
|
|
+ 5 * buttonHeight
|
|
+ (more ?
|
|
(more * (yPadding + buttonHeight) + border + 2)
|
|
: 0)
|
|
+ 2 * border
|
|
);
|
|
}
|
|
}
|
|
|
|
SpriteMorph.prototype.categories.forEach(cat => {
|
|
if (!contains(['lists', 'aa'], cat)) {
|
|
addCategoryButton(cat);
|
|
}
|
|
});
|
|
|
|
// sort alphabetically
|
|
Array.from(
|
|
SpriteMorph.prototype.customCategories.keys()
|
|
).sort().forEach(name =>
|
|
addCustomCategoryButton(
|
|
name,
|
|
SpriteMorph.prototype.customCategories.get(name)
|
|
)
|
|
);
|
|
|
|
fixCategoriesLayout();
|
|
this.add(this.categories);
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.projectMenu = function () {
|
|
var menu,
|
|
myself = this,
|
|
world = this.world(),
|
|
pos = this.controlBar.projectButton.bottomLeft(),
|
|
graphicsName = this.currentSprite instanceof SpriteMorph ?
|
|
'Costumes' : 'Backgrounds',
|
|
shiftClicked = (world.currentKey === 16);
|
|
|
|
// Utility for creating Costumes, etc menus.
|
|
// loadFunction takes in two parameters: a file URL, and a canonical name
|
|
function createMediaMenu(mediaType, loadFunction) {
|
|
return function () {
|
|
var names = this.getMediaList(mediaType),
|
|
mediaMenu = new MenuMorph(
|
|
myself,
|
|
localize('Import') + ' ' + localize(mediaType)
|
|
);
|
|
|
|
names.forEach(function (item) {
|
|
mediaMenu.addItem(
|
|
item.name,
|
|
function () {loadFunction(item.file, item.name); },
|
|
item.help
|
|
);
|
|
});
|
|
mediaMenu.popup(world, pos);
|
|
};
|
|
}
|
|
|
|
menu = new MenuMorph(this);
|
|
menu.addItem('Notes...', 'editNotes');
|
|
menu.addLine();
|
|
menu.addItem('New', 'createNewProject');
|
|
menu.addItem('Open...', 'openProjectsBrowser');
|
|
menu.addItem(
|
|
'Import...',
|
|
function () {
|
|
var inp = document.createElement('input');
|
|
if (myself.filePicker) {
|
|
document.body.removeChild(myself.filePicker);
|
|
myself.filePicker = null;
|
|
}
|
|
inp.type = 'file';
|
|
inp.style.color = "transparent";
|
|
inp.style.backgroundColor = "transparent";
|
|
inp.style.border = "none";
|
|
inp.style.outline = "none";
|
|
inp.style.position = "absolute";
|
|
inp.style.top = "0px";
|
|
inp.style.left = "0px";
|
|
inp.style.width = "0px";
|
|
inp.style.height = "0px";
|
|
inp.addEventListener(
|
|
"change",
|
|
function () {
|
|
document.body.removeChild(inp);
|
|
myself.filePicker = null;
|
|
world.hand.processDrop(inp.files);
|
|
},
|
|
false
|
|
);
|
|
document.body.appendChild(inp);
|
|
myself.filePicker = inp;
|
|
inp.click();
|
|
},
|
|
'file menu import hint' // looks up the actual text in the translator
|
|
);
|
|
menu.addLine();
|
|
menu.addItem('Save', "save");
|
|
menu.addItem('Save As...', 'saveProjectsBrowser');
|
|
//menu.addItem('Save to Disk', 'saveToDisk');
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'Export as SVG',
|
|
function() { myself.downloadSVG(); },
|
|
'Export current drawing as SVG Vector file'
|
|
);
|
|
menu.addItem(
|
|
'Export as DXF',
|
|
function() { myself.downloadDXF(); },
|
|
'Export current drawing as DXF file'
|
|
);
|
|
menu.addItem(
|
|
'Export as PNG',
|
|
function() { myself.downloadPNG(); },
|
|
'Export current drawing as PNG image Vector file'
|
|
);
|
|
menu.addItem(
|
|
'Export as Melco/EXP',
|
|
function() { myself.downloadEXP(); },
|
|
'Export current drawing as EXP/Melco Embroidery file'
|
|
);
|
|
|
|
menu.addItem(
|
|
'Export as Tajima/DST',
|
|
function() { myself.downloadDST(); },
|
|
'Export current drawing as DST/Tajima Embroidery file'
|
|
);
|
|
|
|
if (DEBUG) {
|
|
menu.addItem(
|
|
'Export to Embroidery service',
|
|
function() { myself.uploadOrder(); },
|
|
'Export to stitchcode.com\'s embroidery service'
|
|
);
|
|
}
|
|
|
|
menu.addLine();
|
|
if (shiftClicked) {
|
|
menu.addItem(
|
|
'Export all scripts as pic...',
|
|
function () {myself.exportScriptsPicture(); },
|
|
'show a picture of all scripts\nand block definitions',
|
|
new Color(100, 0, 0)
|
|
);
|
|
}
|
|
menu.addItem(
|
|
'Export project...',
|
|
() => {
|
|
var pn = this.getProjectName();
|
|
if (pn) {
|
|
this.exportProject(pn);
|
|
} else {
|
|
this.prompt(
|
|
'Export Project As...',
|
|
name => this.exportProject(name),
|
|
null,
|
|
'exportProject'
|
|
);
|
|
}
|
|
},
|
|
'save project data as XML\nto your downloads folder'
|
|
);
|
|
|
|
if (this.stage.globalBlocks.length) {
|
|
menu.addItem(
|
|
'Export blocks...',
|
|
function () {myself.exportGlobalBlocks(); },
|
|
'show global custom block definitions as XML' +
|
|
'\nin a new browser window'
|
|
);
|
|
menu.addItem(
|
|
'Unused blocks...',
|
|
function () {myself.removeUnusedBlocks(); },
|
|
'find unused global custom blocks' +
|
|
'\nand remove their definitions'
|
|
);
|
|
}
|
|
|
|
menu.addItem(
|
|
'Export summary...',
|
|
function () {myself.exportProjectSummary(); },
|
|
'open a new browser browser window\n with a summary of this project'
|
|
);
|
|
if (shiftClicked) {
|
|
menu.addItem(
|
|
'Export summary with drop-shadows...',
|
|
function () {myself.exportProjectSummary(true); },
|
|
'open a new browser browser window' +
|
|
'\nwith a summary of this project' +
|
|
'\nwith drop-shadows on all pictures.' +
|
|
'\nnot supported by all browsers',
|
|
new Color(100, 0, 0)
|
|
);
|
|
menu.addItem(
|
|
'Export all scripts as pic...',
|
|
function () {myself.exportScriptsPicture(); },
|
|
'show a picture of all scripts\nand block definitions',
|
|
new Color(100, 0, 0)
|
|
);
|
|
}
|
|
|
|
menu.addLine();
|
|
if (this.stage.globalBlocks.length) {
|
|
menu.addItem(
|
|
'Export blocks...',
|
|
() => this.exportGlobalBlocks(),
|
|
'save global custom block\ndefinitions as XML'
|
|
);
|
|
menu.addItem(
|
|
'Unused blocks...',
|
|
() => this.removeUnusedBlocks(),
|
|
'find unused global custom blocks' +
|
|
'\nand remove their definitions'
|
|
);
|
|
}
|
|
menu.addItem(
|
|
'Hide blocks...',
|
|
() => new BlockVisibilityDialogMorph(this.currentSprite).popUp(world)
|
|
);
|
|
menu.addItem(
|
|
'New category...',
|
|
() => this.createNewCategory()
|
|
);
|
|
if (SpriteMorph.prototype.customCategories.size) {
|
|
menu.addItem(
|
|
'Remove a category...',
|
|
() => this.deleteUserCategory(pos)
|
|
);
|
|
}
|
|
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'Libraries...',
|
|
function() {
|
|
if (location.protocol === 'file:') {
|
|
myself.importLocalFile();
|
|
return;
|
|
}
|
|
myself.getURL(
|
|
myself.resourceURL('libraries', 'LIBRARIES'),
|
|
function (txt) {
|
|
var libraries = myself.parseResourceFile(txt);
|
|
new LibraryImportDialogMorph(myself, libraries).popUp();
|
|
}
|
|
);
|
|
},
|
|
'Select categories of additional blocks to add to this project.'
|
|
);
|
|
|
|
// disable cloud
|
|
/*
|
|
menu.addLine();
|
|
|
|
if (shiftClicked) {
|
|
menu.addItem(
|
|
'Cloud url...',
|
|
'setCloudURL',
|
|
null,
|
|
new Color(100, 0, 0)
|
|
);
|
|
menu.addLine();
|
|
}
|
|
if (!SnapCloud.username) {
|
|
menu.addItem(
|
|
'Login',
|
|
function () { window.open('/login'); }
|
|
);
|
|
menu.addItem(
|
|
'Create an account',
|
|
function () { window.open('/signup'); }
|
|
);
|
|
menu.addItem(
|
|
'Reset Password...',
|
|
function () { window.open('/forgot_password'); }
|
|
);
|
|
} else {
|
|
menu.addItem(
|
|
localize('Logout') + ' / ' + SnapCloud.username,
|
|
'logout'
|
|
);
|
|
}
|
|
*/
|
|
if (shiftClicked) {
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'export project media only...',
|
|
function () {
|
|
if (myself.projectName) {
|
|
myself.exportProjectMedia(myself.projectName);
|
|
} else {
|
|
myself.prompt('Export Project As...', function (name) {
|
|
myself.exportProjectMedia(name);
|
|
}, null, 'exportProject');
|
|
}
|
|
},
|
|
null,
|
|
this.hasChangedMedia ? new Color(100, 0, 0) : new Color(0, 100, 0)
|
|
);
|
|
menu.addItem(
|
|
'export project without media...',
|
|
function () {
|
|
if (myself.projectName) {
|
|
myself.exportProjectNoMedia(myself.projectName);
|
|
} else {
|
|
myself.prompt('Export Project As...', function (name) {
|
|
myself.exportProjectNoMedia(name);
|
|
}, null, 'exportProject');
|
|
}
|
|
},
|
|
null,
|
|
new Color(100, 0, 0)
|
|
);
|
|
menu.addItem(
|
|
'export project as cloud data...',
|
|
function () {
|
|
if (myself.projectName) {
|
|
myself.exportProjectAsCloudData(myself.projectName);
|
|
} else {
|
|
myself.prompt('Export Project As...', function (name) {
|
|
myself.exportProjectAsCloudData(name);
|
|
}, null, 'exportProject');
|
|
}
|
|
},
|
|
null,
|
|
new Color(100, 0, 0)
|
|
);
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'open shared project from cloud...',
|
|
function () {
|
|
myself.prompt('Author name…', function (usr) {
|
|
myself.prompt('Project name...', function (prj) {
|
|
var id = 'Username=' +
|
|
encodeURIComponent(usr.toLowerCase()) +
|
|
'&ProjectName=' +
|
|
encodeURIComponent(prj);
|
|
myself.showMessage(
|
|
'Fetching project\nfrom the cloud...'
|
|
);
|
|
SnapCloud.getPublicProject(
|
|
id,
|
|
function (projectData) {
|
|
var msg;
|
|
if (!Process.prototype.isCatchingErrors) {
|
|
window.open(
|
|
'data:text/xml,' + projectData
|
|
);
|
|
}
|
|
myself.nextSteps([
|
|
function () {
|
|
msg = myself.showMessage(
|
|
'Opening project...'
|
|
);
|
|
},
|
|
function () {nop(); }, // yield (Chrome)
|
|
function () {
|
|
myself.rawOpenCloudDataString(
|
|
projectData
|
|
);
|
|
},
|
|
function () {
|
|
msg.destroy();
|
|
}
|
|
]);
|
|
},
|
|
myself.cloudError()
|
|
);
|
|
|
|
}, null, 'project');
|
|
}, null, 'project');
|
|
},
|
|
null,
|
|
new Color(100, 0, 0)
|
|
);
|
|
}
|
|
|
|
menu.popup(world, pos);
|
|
};
|
|
|
|
IDE_Morph.prototype.snapMenu = function () {
|
|
var menu,
|
|
world = this.world();
|
|
|
|
menu = new MenuMorph(this);
|
|
menu.addItem('About TurtleStitch...', 'aboutTurtleStitch');
|
|
menu.addItem('About Snap!...', 'aboutSnap');
|
|
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'Reference manual',
|
|
function () {
|
|
window.open('help/SnapManual.pdf', 'SnapReferenceManual');
|
|
}
|
|
);
|
|
menu.addItem(
|
|
'TurtleStitch Web Site',
|
|
function () {
|
|
window.open('http://www.turtlestitch.org', 'TurtleStitchWebsite');
|
|
}
|
|
);
|
|
menu.addItem(
|
|
'Snap! website',
|
|
function () {
|
|
window.open('http://snap.berkeley.edu/', 'SnapWebsite');
|
|
}
|
|
);
|
|
menu.addItem(
|
|
'Download source',
|
|
function () {
|
|
window.open(
|
|
'https://github.com/backface/turtlestitch',
|
|
'Turtlestitchsource'
|
|
);
|
|
}
|
|
);
|
|
if (world.isDevMode) {
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'Switch back to user mode',
|
|
'switchToUserMode',
|
|
'disable deep-Morphic\ncontext menus'
|
|
+ '\nand show user-friendly ones',
|
|
new Color(0, 100, 0)
|
|
);
|
|
} else if (world.currentKey === 16) { // shift-click
|
|
menu.addLine();
|
|
menu.addItem(
|
|
'Switch to dev mode',
|
|
'switchToDevMode',
|
|
'enable Morphic\ncontext menus\nand inspectors,'
|
|
+ '\nnot user-friendly!',
|
|
new Color(100, 0, 0)
|
|
);
|
|
}
|
|
menu.popup(world, this.logo.bottomLeft());
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.originalCreateSpriteEditor = IDE_Morph.prototype.createSpriteEditor;
|
|
IDE_Morph.prototype.createSpriteEditor = function(){
|
|
this.originalCreateSpriteEditor();
|
|
this.spriteEditor.color = new Color(240, 240, 240);
|
|
this.currentSprite.scripts.color = new Color(240, 240, 240);
|
|
this.spriteEditor.mouseEnterDragging = nop;
|
|
this.spriteEditor.contents.mouseEnterDragging =nop;
|
|
};
|
|
|
|
/* CORRAL BAR */
|
|
// Single Sprite mode, no corral and no tabs in the scripting area
|
|
IDE_Morph.prototype.createCorralBar = nop;
|
|
IDE_Morph.prototype.createCorral = nop;
|
|
|
|
IDE_Morph.prototype.selectSprite = function (sprite) {
|
|
this.currentSprite = sprite;
|
|
this.createPalette();
|
|
this.createSpriteEditor();
|
|
this.fixLayout('selectSprite');
|
|
this.currentSprite.scripts.fixMultiArgs();
|
|
};
|
|
|
|
// Addressing #54: Stage occasionally goes blank
|
|
IDE_Morph.prototype.originalRefreshPalette = IDE_Morph.prototype.refreshPalette;
|
|
IDE_Morph.prototype.refreshPalette = function (shouldIgnorePosition) {
|
|
this.originalRefreshPalette(shouldIgnorePosition);
|
|
this.stage.reRender();
|
|
};
|
|
|
|
// Language
|
|
|
|
IDE_Morph.prototype.originalSetLanguage = IDE_Morph.prototype.setLanguage;
|
|
IDE_Morph.prototype.setLanguage = function(lang, callback) {
|
|
var myself = this;
|
|
|
|
myself.originalSetLanguage(lang, function () {
|
|
var translation = document.getElementById('bb-language'),
|
|
src = 'stitchcode/locales/lang-' + lang + '.js',
|
|
myInnerSelf = this;
|
|
if (translation) {
|
|
document.head.removeChild(translation);
|
|
}
|
|
if (lang === 'en') {
|
|
return this.reflectLanguage('en', callback);
|
|
}
|
|
translation = document.createElement('script');
|
|
translation.id = 'bb-language';
|
|
translation.onload = function () {
|
|
myInnerSelf.reflectLanguage(lang, callback);
|
|
};
|
|
document.head.appendChild(translation);
|
|
translation.src = src;
|
|
});
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.setStageExtent = function (aPoint) {
|
|
var myself = this,
|
|
world = this.world(),
|
|
ext = aPoint.max(new Point(480, 180));
|
|
|
|
function zoom() {
|
|
myself.step = function () {
|
|
var delta = ext.subtract(
|
|
StageMorph.prototype.dimensions
|
|
).divideBy(2);
|
|
if (delta.abs().lt(new Point(5, 5))) {
|
|
StageMorph.prototype.dimensions = ext;
|
|
delete myself.step;
|
|
} else {
|
|
StageMorph.prototype.dimensions =
|
|
StageMorph.prototype.dimensions.add(delta);
|
|
}
|
|
myself.stage.setExtent(StageMorph.prototype.dimensions);
|
|
myself.stage.clearPenTrails();
|
|
myself.fixLayout();
|
|
this.setExtent(world.extent());
|
|
this.stage.initCamera();
|
|
};
|
|
}
|
|
|
|
this.stageRatio = 1;
|
|
this.isSmallStage = false;
|
|
this.controlBar.stageSizeButton.refresh();
|
|
this.setExtent(world.extent());
|
|
if (this.isAnimating) {
|
|
zoom();
|
|
} else {
|
|
StageMorph.prototype.dimensions = ext;
|
|
this.stage.setExtent(StageMorph.prototype.dimensions);
|
|
this.stage.clearPenTrails();
|
|
this.fixLayout();
|
|
this.setExtent(world.extent());
|
|
}
|
|
this.stage.initCamera();
|
|
};
|
|
|
|
|
|
DialogBoxMorph.prototype.promptOrder = function (
|
|
title,
|
|
tosURL,
|
|
tosLabel,
|
|
prvURL,
|
|
prvLabel,
|
|
PUBCheckBoxLabel,
|
|
TOSCheckBoxLabel,
|
|
world,
|
|
pic,
|
|
msg
|
|
) {
|
|
var usr = new InputFieldMorph(),
|
|
bmn,
|
|
agreeTOS = true,
|
|
agreePUB = true,
|
|
chk_tos,
|
|
chk_pub,
|
|
mCol = new AlignmentMorph('column', 1),
|
|
yCol = new AlignmentMorph('column', 1),
|
|
lnk = new AlignmentMorph('row', 1),
|
|
bdy = new AlignmentMorph('column', this.padding),
|
|
myself = this;
|
|
|
|
function labelText(string) {
|
|
return new TextMorph(
|
|
localize(string),
|
|
10,
|
|
null, // style
|
|
false, // bold
|
|
null, // italic
|
|
null, // alignment
|
|
null, // width
|
|
null, // font name
|
|
MorphicPreferences.isFlat ? null : new Point(1, 1),
|
|
new Color(255, 255, 255) // shadowColor
|
|
);
|
|
}
|
|
|
|
function linkButton(label, url) {
|
|
var btn = new PushButtonMorph(
|
|
myself,
|
|
function () {
|
|
window.open(url);
|
|
},
|
|
' ' + localize(label) + ' '
|
|
);
|
|
btn.fontSize = 10;
|
|
btn.corner = myself.buttonCorner;
|
|
btn.edge = myself.buttonEdge;
|
|
btn.outline = myself.buttonOutline;
|
|
btn.outlineColor = myself.buttonOutlineColor;
|
|
btn.outlineGradient = myself.buttonOutlineGradient;
|
|
btn.padding = myself.buttonPadding;
|
|
btn.contrast = myself.buttonContrast;
|
|
// btn.fixLayout();
|
|
btn.fixLayout();
|
|
return btn;
|
|
}
|
|
|
|
|
|
bdy.setColor(this.color);
|
|
|
|
mCol.alignment = 'left';
|
|
mCol.setColor(this.color);
|
|
yCol.alignment = 'left';
|
|
yCol.setColor(this.color);
|
|
|
|
|
|
if (msg) {
|
|
bdy.add(labelText(msg));
|
|
}
|
|
|
|
if (tosURL || prvURL) {
|
|
bdy.add(lnk);
|
|
}
|
|
if (tosURL) {
|
|
lnk.add(linkButton(tosLabel, tosURL));
|
|
}
|
|
if (prvURL) {
|
|
lnk.add(linkButton(prvLabel, prvURL));
|
|
}
|
|
|
|
if (PUBCheckBoxLabel) {
|
|
chk_pub = new ToggleMorph(
|
|
'checkbox',
|
|
this,
|
|
function () {agreePUB = !agreePUB; }, // action,
|
|
PUBCheckBoxLabel,
|
|
function () {return agreePUB; } //query
|
|
);
|
|
chk_pub.edge = this.buttonEdge / 2;
|
|
chk_pub.outline = this.buttonOutline / 2;
|
|
chk_pub.outlineColor = this.buttonOutlineColor;
|
|
chk_pub.outlineGradient = this.buttonOutlineGradient;
|
|
chk_pub.contrast = this.buttonContrast;
|
|
// chk_pub.fixLayout();
|
|
chk_pub.fixLayout();
|
|
bdy.add(chk_pub);
|
|
}
|
|
|
|
if (TOSCheckBoxLabel) {
|
|
chk_tos = new ToggleMorph(
|
|
'checkbox',
|
|
this,
|
|
function () {agreeTOS = !agreeTOS; }, // action,
|
|
TOSCheckBoxLabel,
|
|
function () {return agreeTOS; } //query
|
|
);
|
|
chk_tos.edge = this.buttonEdge / 2;
|
|
chk_tos.outline = this.buttonOutline / 2;
|
|
chk_tos.outlineColor = this.buttonOutlineColor;
|
|
chk_tos.outlineGradient = this.buttonOutlineGradient;
|
|
chk_tos.contrast = this.buttonContrast;
|
|
// chk_tos.fixLayout();
|
|
chk_tos.fixLayout();
|
|
bdy.add(chk_tos);
|
|
}
|
|
|
|
|
|
mCol.fixLayout();
|
|
yCol.fixLayout();
|
|
lnk.fixLayout();
|
|
bdy.fixLayout();
|
|
|
|
this.labelString = title;
|
|
this.createLabel();
|
|
if (pic) {this.setPicture(pic); }
|
|
|
|
this.addBody(bdy);
|
|
|
|
// mCol.fixLayout();
|
|
// yCol.fixLayout();
|
|
bdy.fixLayout();
|
|
|
|
this.addButton('ok', 'OK');
|
|
this.addButton('cancel', 'Cancel');
|
|
this.fixLayout();
|
|
// this.fixLayout();
|
|
this.fixLayout();
|
|
|
|
function validInputs() {
|
|
|
|
function indicate(morph, string) {
|
|
var bubble = new SpeechBubbleMorph(localize(string));
|
|
bubble.isPointingRight = false;
|
|
// bubble.fixLayout();
|
|
bubble.popUp(
|
|
world,
|
|
morph.leftCenter().subtract(new Point(bubble.width() + 2, 0))
|
|
);
|
|
if (morph.edit) {
|
|
morph.edit();
|
|
}
|
|
}
|
|
|
|
|
|
if (!agreeTOS) {
|
|
indicate(chk_tos, 'please agree to\nthe TOS');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
this.accept = function () {
|
|
if (validInputs()) {
|
|
DialogBoxMorph.prototype.accept.call(myself);
|
|
}
|
|
};
|
|
|
|
|
|
this.getInput = function () {
|
|
return {
|
|
choice_pub: agreePUB
|
|
};
|
|
};
|
|
|
|
this.reactToChoice = function () {
|
|
};
|
|
|
|
this.reactToChoice(); // initialize e-mail label
|
|
|
|
if (!this.key) {
|
|
this.key = 'order';
|
|
}
|
|
|
|
this.popUp(world);
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.uploadOrder = function () {
|
|
var myself = this,
|
|
world = this.world();
|
|
|
|
if (window.location.hostname.endsWith("localhost")) {
|
|
SHOP_URL = 'http://shop.stitchcode.localhost/ext.php';
|
|
} else {
|
|
SHOP_URL = 'http://shop.stitchcode.com/ext.php';
|
|
}
|
|
|
|
if (myself.stage.turtleShepherd.hasSteps()) {
|
|
new DialogBoxMorph(
|
|
this,
|
|
function(userdata) {
|
|
expUintArr = this.stage.turtleShepherd.toDST();
|
|
blob_dst = new Blob([expUintArr], {type: 'application/octet-stream'});
|
|
expUintArr = this.stage.turtleShepherd.toEXP();
|
|
blob_exp = new Blob([expUintArr], {type: 'application/octet-stream'});
|
|
|
|
var fd = new FormData;
|
|
var name = (this.projectName ? this.projectName : 'turtlestitch')
|
|
fd.append('public', userdata.choice_pub);
|
|
fd.append('filename', name + ".dst");
|
|
fd.append('projectname', name);
|
|
fd.append('source', 'turtlestitch');
|
|
fd.append('url', window.location.href);
|
|
fd.append('dstfile', blob_dst, name + ".dst");
|
|
fd.append('expfile', blob_exp, name + ".exp");
|
|
if (SnapCloud.username)
|
|
fd.append('username', SnapCloud.username);
|
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
request.onreadystatechange = function () {
|
|
if (request.readyState === 4) {
|
|
if (request.responseText) {
|
|
try {
|
|
var response = JSON.parse(request.responseText);
|
|
if (!response.error) {
|
|
new DialogBoxMorph().informWithLink(
|
|
'Upload success',
|
|
'Your embroidery was successully uploaded.\n\n Procceed to order opening a new window.\n'
|
|
+ 'If it does not open automatically, click here:' ,
|
|
response.url,
|
|
world);
|
|
window.open(response.url);
|
|
}
|
|
} catch(e) {
|
|
new DialogBoxMorph().inform(
|
|
'Upload Error',
|
|
'Sorry. There was an Error during upload: \n' + request.responseText,
|
|
world);
|
|
}
|
|
|
|
|
|
} else {
|
|
new DialogBoxMorph().inform(
|
|
'Upload Error',
|
|
'Sorry. There was an Error during upload: \n'
|
|
+ request.responseText + "\n"
|
|
+ request.status + ' - ' + request.statusText,
|
|
world);
|
|
}
|
|
}
|
|
};
|
|
|
|
//url = url + ((/\?x=/).test(url) ? "&" : "?") + (new Date()).getTime();
|
|
request.open('POST', SHOP_URL, true);
|
|
request.send(fd);
|
|
}, // fntion
|
|
this
|
|
).promptOrder(
|
|
'Upload Order',
|
|
'http://snap.berkeley.edu/tos.html',
|
|
'Terms of Service...',
|
|
'',
|
|
'',
|
|
'Upload project as public (domain)',
|
|
'I have read and agree\nto the Terms of Service',
|
|
world,
|
|
null, //new SymbolMorph("turtle"), //icon
|
|
null // msg
|
|
);
|
|
} else {
|
|
new DialogBoxMorph().inform(
|
|
'Upload Error',
|
|
'No stitches to upload, please (re)generate a drawing first!',
|
|
world);
|
|
}
|
|
};
|
|
|
|
DialogBoxMorph.prototype.informWithLink = function (
|
|
title,
|
|
textString,
|
|
url,
|
|
world,
|
|
pic
|
|
) {
|
|
var lnk = new AlignmentMorph('row', 1);
|
|
var txt = new TextMorph(
|
|
textString,
|
|
this.fontSize,
|
|
this.fontStyle,
|
|
true,
|
|
false,
|
|
'center',
|
|
null,
|
|
null,
|
|
MorphicPreferences.isFlat ? null : new Point(1, 1),
|
|
new Color(255, 255, 255)
|
|
),
|
|
bdy = new AlignmentMorph('column', this.padding),
|
|
myself = this;
|
|
|
|
function linkButton(label, url) {
|
|
var btn = new PushButtonMorph(
|
|
myself,
|
|
function () {
|
|
window.open(url);
|
|
},
|
|
' ' + localize(label) + ' '
|
|
);
|
|
btn.fontSize = 10;
|
|
btn.corner = myself.buttonCorner;
|
|
btn.edge = myself.buttonEdge;
|
|
btn.outline = myself.buttonOutline;
|
|
btn.outlineColor = myself.buttonOutlineColor;
|
|
btn.outlineGradient = myself.buttonOutlineGradient;
|
|
btn.padding = myself.buttonPadding;
|
|
btn.contrast = myself.buttonContrast;
|
|
// btn.fixLayout();
|
|
btn.fixLayout();
|
|
return btn;
|
|
}
|
|
|
|
if (!this.key) {
|
|
this.key = 'inform' + title + textString;
|
|
}
|
|
|
|
this.labelString = title;
|
|
this.createLabel();
|
|
if (pic) {this.setPicture(pic); }
|
|
|
|
if (textString) {
|
|
bdy.add(txt)
|
|
}
|
|
|
|
if (url) {
|
|
lnk.add(linkButton(url, url));
|
|
bdy.add(lnk);
|
|
}
|
|
|
|
bdy.fixLayout();
|
|
|
|
this.addBody(bdy);
|
|
|
|
this.addButton('ok', 'OK');
|
|
// this.fixLayout();
|
|
this.fixLayout();
|
|
this.popUp(world);
|
|
};
|
|
|
|
ProjectDialogMorph.prototype.installCloudProjectList = function (pl) {
|
|
this.projectList = pl[0] ? pl : [];
|
|
this.projectList.sort((x, y) =>
|
|
x.projectname.toLowerCase() < y.projectname.toLowerCase() ? -1 : 1
|
|
);
|
|
|
|
this.listField.destroy();
|
|
this.listField = new ListMorph(
|
|
this.projectList,
|
|
this.projectList.length > 0 ?
|
|
(element) => {return element.projectname || element; }
|
|
: null,
|
|
[ // format: display shared project names bold
|
|
[
|
|
'bold',
|
|
proj => proj.ispublic
|
|
],
|
|
[
|
|
'italic',
|
|
proj => proj.ispublished
|
|
]
|
|
],
|
|
() => this.ok()
|
|
);
|
|
this.fixListFieldItemColors();
|
|
this.listField.fixLayout = nop;
|
|
this.listField.edge = InputFieldMorph.prototype.edge;
|
|
this.listField.fontSize = InputFieldMorph.prototype.fontSize;
|
|
this.listField.typeInPadding = InputFieldMorph.prototype.typeInPadding;
|
|
this.listField.contrast = InputFieldMorph.prototype.contrast;
|
|
this.listField.render = InputFieldMorph.prototype.render;
|
|
this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder;
|
|
|
|
this.listField.action = (item) => {
|
|
if (item === undefined) {return; }
|
|
if (this.nameField) {
|
|
this.nameField.setContents(item.projectname || '');
|
|
}
|
|
if (this.task === 'open' || this.task === 'add') {
|
|
this.notesText.text = item.notes || '';
|
|
this.notesText.rerender();
|
|
this.notesField.contents.adjustBounds();
|
|
this.preview.texture = '';
|
|
this.preview.rerender();
|
|
// we ask for the thumbnail when selecting a project
|
|
this.ide.cloud.getThumbnail(
|
|
null, // username is implicit
|
|
item.projectname,
|
|
thumbnail => {
|
|
this.preview.texture = thumbnail;
|
|
this.preview.cachedTexture = null;
|
|
this.preview.rerender();
|
|
});
|
|
new SpeechBubbleMorph(new TextMorph(
|
|
localize('last changed') + '\n' + item.updated + item.ispublic + item.Public,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'center'
|
|
)).popUp(
|
|
this.world(),
|
|
this.preview.rightCenter().add(new Point(2, 0))
|
|
);
|
|
}
|
|
if (item.ispublic) {
|
|
this.shareButton.hide();
|
|
this.unshareButton.show();
|
|
} else {
|
|
this.unshareButton.hide();
|
|
this.shareButton.show();
|
|
}
|
|
this.buttons.fixLayout();
|
|
this.fixLayout();
|
|
this.publishButton.hide();
|
|
this.edit();
|
|
|
|
};
|
|
this.body.add(this.listField);
|
|
if (this.task === 'open' || this.task === 'add') {
|
|
this.recoverButton.hide();
|
|
this.tagsField.hide();
|
|
this.tagsLabelField.hide();
|
|
this.unshareButton.hide();
|
|
this.shareButton.hide();
|
|
this.unpublishButton.hide();
|
|
}
|
|
this.deleteButton.show();
|
|
this.buttons.fixLayout();
|
|
this.fixLayout();
|
|
if (this.task === 'open' || this.task === 'add') {
|
|
this.clearDetails();
|
|
}
|
|
};
|
|
|
|
/*
|
|
|
|
|
|
ProjectDialogMorph.prototype.installCloudProjectList = function (pl) {
|
|
var myself = this;
|
|
this.projectList = pl || [];
|
|
this.projectList.sort(function (x, y) {
|
|
return x.ProjectName.toLowerCase() < y.ProjectName.toLowerCase() ?
|
|
-1 : 1;
|
|
});
|
|
|
|
this.listField.destroy();
|
|
this.listField = new ListMorph(
|
|
this.projectList,
|
|
this.projectList.length > 0 ?
|
|
function (element) {
|
|
return element.ProjectName || element;
|
|
} : null,
|
|
[ // format: display shared project names bold
|
|
[
|
|
'bold',
|
|
function (proj) {return proj.Public === 'true'; }
|
|
]
|
|
],
|
|
function () {myself.ok(); }
|
|
);
|
|
this.fixListFieldItemColors();
|
|
this.listField.fixLayout = nop;
|
|
this.listField.edge = InputFieldMorph.prototype.edge;
|
|
this.listField.fontSize = InputFieldMorph.prototype.fontSize;
|
|
this.listField.typeInPadding = InputFieldMorph.prototype.typeInPadding;
|
|
this.listField.contrast = InputFieldMorph.prototype.contrast;
|
|
// this.listField.fixLayout = InputFieldMorph.prototype.fixLayout;
|
|
this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder;
|
|
|
|
this.listField.action = function (item) {
|
|
if (item === undefined) {return; }
|
|
if (myself.nameField) {
|
|
myself.nameField.setContents(item.ProjectName || '');
|
|
}
|
|
if (myself.task === 'open') {
|
|
myself.notesText.text = item.Notes || '';
|
|
// myself.notesText.fixLayout();
|
|
myself.notesText.fixLayout();
|
|
myself.notesField.contents.adjustBounds();
|
|
myself.preview.texture = item.Thumbnail || null;
|
|
myself.preview.cachedTexture = null;
|
|
// myself.preview.fixLayout();
|
|
myself.preview.fixLayout();
|
|
(new SpeechBubbleMorph(new TextMorph(
|
|
localize('last changed') + '\n' + item.Updated,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'center'
|
|
))).popUp(
|
|
myself.world(),
|
|
myself.preview.rightCenter().add(new Point(2, 0))
|
|
);
|
|
}
|
|
if (item.Public === 'true') {
|
|
myself.shareButton.hide();
|
|
myself.unshareButton.show();
|
|
} else {
|
|
myself.unshareButton.hide();
|
|
myself.shareButton.show();
|
|
}
|
|
myself.buttons.fixLayout();
|
|
myself.fixLayout();
|
|
myself.edit();
|
|
};
|
|
this.body.add(this.listField);
|
|
this.shareButton.show();
|
|
this.unshareButton.hide();
|
|
this.deleteButton.show();
|
|
this.buttons.fixLayout();
|
|
this.fixLayout();
|
|
if (this.task === 'open') {
|
|
this.clearDetails();
|
|
}
|
|
};
|
|
|
|
*/
|
|
ProjectDialogMorph.prototype.fixLayoutOrig = ProjectDialogMorph.prototype.fixLayout;
|
|
ProjectDialogMorph.prototype.initOrig = ProjectDialogMorph.prototype.init;
|
|
ProjectDialogMorph.prototype.saveProjectOrig = ProjectDialogMorph.prototype.saveProject;
|
|
|
|
|
|
ProjectDialogMorph.prototype.fixLayout = function () {
|
|
this.fixLayoutOrig();
|
|
var th = fontHeight(this.titleFontSize) + this.titlePadding * 2,
|
|
thin = this.padding / 2,
|
|
oldFlag = Morph.prototype.trackChanges;
|
|
|
|
if (this.preview) {
|
|
this.preview.setHeight(310);
|
|
}
|
|
if (this.body && this.tagsField) {
|
|
this.notesLabelField.setTop(this.preview.bottom() + thin);
|
|
this.notesLabelField.setLeft(this.preview.left() + 1);
|
|
this.notesField.setTop(this.notesLabelField.bottom());
|
|
this.notesField.setLeft(this.preview.left());
|
|
this.notesField.setHeight(this.body.bottom() - this.notesLabelField.bottom() - this.notesLabelField.height() - thin);
|
|
this.tagsLabelField.setTop(this.notesField.bottom() + thin);
|
|
this.tagsLabelField.setLeft(this.notesField.left() + 1);
|
|
this.tagsField.setTop(this.notesField.bottom() + 2);
|
|
this.tagsField.setLeft(this.tagsLabelField.right());
|
|
this.tagsField.setWidth(this.notesField.width() - this.tagsLabelField.width() - 1);
|
|
}
|
|
this.changed();
|
|
}
|
|
|
|
|
|
ProjectDialogMorph.prototype.init = function (ide, task) {
|
|
this.initOrig (ide, task);
|
|
this.tagsText = "Tags?";
|
|
}
|
|
|
|
ProjectDialogMorph.prototype.saveProjectOrig = ProjectDialogMorph.prototype.saveProject;
|
|
ProjectDialogMorph.prototype.saveProject = function () {
|
|
this.ide.tags = this.tagsField.contents().text.text;
|
|
this.saveProjectOrig();
|
|
};
|
|
|
|
|
|
StageMorph.prototype.backgroundColor = new Color(255,255,255);
|
|
StageMorph.prototype.defaultPenColor = new Color(0,0,0,1);
|
|
|
|
IDE_Morph.prototype.userSetBackgroundColor = function () {
|
|
new DialogBoxMorph(
|
|
this,
|
|
function (value) {
|
|
this.stage.renderer.setBackgroundColorHex(value);
|
|
if (value != '#ffffff')
|
|
this.saveSetting('backgroundColor', value);
|
|
else {
|
|
this.removeSetting('backgroundColor');
|
|
}
|
|
},
|
|
this
|
|
).prompt(
|
|
"Default background color",
|
|
new String("#" + ((1 << 24)
|
|
+ (Math.round(StageMorph.prototype.backgroundColor.r) << 16)
|
|
+ (Math.round(StageMorph.prototype.backgroundColor.g) << 8)
|
|
+ Math.round(StageMorph.prototype.backgroundColor.b)).toString(16).slice(1)),
|
|
this.world(),
|
|
null, // pic
|
|
null, // choices
|
|
null, // read only
|
|
false // numeric
|
|
);
|
|
};
|
|
|
|
IDE_Morph.prototype.userSetPenColor = function () {
|
|
new DialogBoxMorph(
|
|
this,
|
|
function (value) {
|
|
this.stage.renderer.setDefaultPenColorHex(value);
|
|
this.currentSprite.setColor(StageMorph.prototype.defaultPenColor);
|
|
if (value != '#000000')
|
|
this.saveSetting('defaultPenColor', value);
|
|
else {
|
|
this.removeSetting('defaultPenColor');
|
|
}
|
|
},
|
|
this
|
|
).prompt(
|
|
"Default pen color",
|
|
new String("#" + ((1 << 24)
|
|
+ (Math.round(StageMorph.prototype.defaultPenColor.r) << 16)
|
|
+ (Math.round(StageMorph.prototype.defaultPenColor.g) << 8)
|
|
+ Math.round(StageMorph.prototype.defaultPenColor.b)).toString(16).slice(1)),
|
|
this.world(),
|
|
null, // pic
|
|
null, // choices
|
|
null, // read only
|
|
false // numeric
|
|
);
|
|
};
|
|
|
|
IDE_Morph.prototype.loadCameraSnapshot = function () {
|
|
this.stage.loadCameraSnapshot()
|
|
};
|
|
|
|
IDE_Morph.prototype.clearStageBackground = function () {
|
|
this.stage.clearStageBackground()
|
|
};
|
|
|
|
|
|
IDE_Morph.prototype.droppedImage = function (aCanvas, name) {
|
|
var myself = this;
|
|
var stage = this.stage;
|
|
var costume = new Costume(
|
|
aCanvas,
|
|
this.stage.newCostumeName(
|
|
name ? name.split('.')[0] : '' // up to period
|
|
)
|
|
);
|
|
if (costume.isTainted()) {
|
|
this.inform(
|
|
'Unable to import this image',
|
|
'The picture you wish to import has been\n' +
|
|
'tainted by a restrictive cross-origin policy\n' +
|
|
'making it unusable for costumes in Snap!. \n\n' +
|
|
'Try downloading this picture first to your\n' +
|
|
'computer, and import it from there.'
|
|
);
|
|
return;
|
|
}
|
|
this.loadAsBackgroundOrData(costume, name)
|
|
}
|
|
|
|
IDE_Morph.prototype.loadAsBackgroundOrData = function (costume, name) {
|
|
var myself = this;
|
|
var stage = this.stage;
|
|
var dlg, world = this.world();
|
|
dlg = new DialogBoxMorph();
|
|
dlg.labelString = localize('Import Image');
|
|
dlg.createLabel();c
|
|
|
|
var txt = new TextMorph(
|
|
localize('Import Image as Background or as data table into a variable?'),
|
|
dlg.fontSize,
|
|
dlg.fontStyle,
|
|
true,
|
|
false,
|
|
'center',
|
|
null,
|
|
null,
|
|
MorphicPreferences.isFlat ? null : new Point(1, 1),
|
|
WHITE
|
|
);
|
|
dlg.addBody(txt);
|
|
|
|
btn1 = dlg.addButton(
|
|
function () {
|
|
stage.addCostume(costume);
|
|
stage.wearCostume(costume);
|
|
stage.hasBackgroundImage = true;
|
|
stage.renderer.setClearColor(
|
|
new THREE.Color(
|
|
"rgb("+
|
|
StageMorph.prototype.backgroundColor.r + "," +
|
|
StageMorph.prototype.backgroundColor.g + "," +
|
|
StageMorph.prototype.backgroundColor.b + ")"),
|
|
stage.hasBackgroundImage ? 0.5 : 1
|
|
);
|
|
myself.hasChangedMedia = true;
|
|
myself.recordUnsavedChanges();
|
|
this.destroy();
|
|
},
|
|
'As background'
|
|
);
|
|
btn2 = dlg.addButton(
|
|
function () {
|
|
myself.rawOpenImageData(costume.rasterized().pixels(), name)
|
|
this.destroy();
|
|
},
|
|
'As data',
|
|
);
|
|
dlg.fixLayout();
|
|
dlg.popUp(world);
|
|
}
|
|
|
|
|
|
IDE_Morph.prototype.loadSVG = function (anImage, name) {
|
|
var costume = new SVG_Costume(anImage, name);
|
|
var stage = this.stage;
|
|
this.stage.addCostume(costume);
|
|
this.stage.wearCostume(costume);
|
|
this.stage.hasBackgroundImage = true;
|
|
this.stage.renderer.setClearColor(
|
|
new THREE.Color(
|
|
"rgb("+
|
|
StageMorph.prototype.backgroundColor.r + "," +
|
|
StageMorph.prototype.backgroundColor.g + "," +
|
|
StageMorph.prototype.backgroundColor.b + ")"),
|
|
stage.hasBackgroundImage ? 0.0 : 1
|
|
);
|
|
this.hasChangedMedia = true;
|
|
};
|
|
|
|
IDE_Morph.prototype.droppedAudio = function (anAudio, name) {
|
|
// ignore
|
|
};
|
|
|
|
IDE_Morph.prototype.rawOpenImageData = function (data, name) {
|
|
var data, vName, dlg,
|
|
globals = this.currentSprite.globalVariables();
|
|
|
|
function newVarName(name) {
|
|
var existing = globals.names(),
|
|
ix = name.indexOf('\('),
|
|
stem = (ix < 0) ? name : name.substring(0, ix),
|
|
count = 1,
|
|
newName = stem;
|
|
while (contains(existing, newName)) {
|
|
count += 1;
|
|
newName = stem + '(' + count + ')';
|
|
}
|
|
return newName;
|
|
}
|
|
|
|
vName = newVarName(name || 'data');
|
|
globals.addVar(vName);
|
|
globals.setVar(vName, data);
|
|
this.currentSprite.toggleVariableWatcher(vName, false); // global
|
|
this.flushBlocksCache('variables');
|
|
this.currentCategory = 'variables';
|
|
this.categories.children.forEach(each =>
|
|
each.refresh()
|
|
);
|
|
this.refreshPalette(true);
|
|
if (data instanceof List) {
|
|
dlg = new TableDialogMorph(data);
|
|
dlg.labelString = localize(dlg.labelString) + ': ' + vName;
|
|
dlg.createLabel();
|
|
dlg.popUp(this.world());
|
|
}
|
|
};
|
|
|
|
|
|
// ------
|
|
// override switch to scene without touching albums or corrals
|
|
|
|
IDE_Morph.prototype.switchToScene = function (
|
|
scene,
|
|
refreshAlbum,
|
|
msg,
|
|
pauseHats
|
|
) {
|
|
var appMode = this.isAppMode;
|
|
if (!scene || !scene.stage) {
|
|
return;
|
|
}
|
|
this.siblings().forEach(morph =>
|
|
morph.destroy()
|
|
);
|
|
this.scene.captureGlobalSettings();
|
|
this.scene = scene;
|
|
this.globalVariables = scene.globalVariables;
|
|
this.stage.destroy();
|
|
this.add(scene.stage);
|
|
this.stage = scene.stage;
|
|
this.sprites = scene.sprites;
|
|
if (pauseHats) {
|
|
this.stage.pauseGenericHatBlocks();
|
|
}
|
|
// this.createCorral(!refreshAlbum); // keep scenes
|
|
this.selectSprite(this.scene.currentSprite, true);
|
|
// this.corral.album.updateSelection();
|
|
this.fixLayout();
|
|
|
|
scene.applyGlobalSettings();
|
|
|
|
this.toggleAppMode(appMode);
|
|
this.controlBar.stopButton.refresh();
|
|
this.world().keyboardFocus = this.stage;
|
|
if (msg) {
|
|
this.stage.fireChangeOfSceneEvent(msg);
|
|
}
|
|
};
|
|
|
|
IDE_Morph.prototype.openProjectName = function (name) {
|
|
var str;
|
|
if (name) {
|
|
this.showMessage('opening project\n' + name);
|
|
this.setProjectName(name);
|
|
str = localStorage['-snap-project-' + name];
|
|
this.openProjectString(str);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
StageHandleMorph.prototype.init = function (target) {
|
|
this.target = target || null;
|
|
HandleMorph.uber.init.call(this);
|
|
this.color = MorphicPreferences.isFlat ?
|
|
new Color(125, 125, 125) : new Color(190, 190, 190);
|
|
this.isDraggable = false;
|
|
this.noticesTransparentClick = true;
|
|
this.setExtent(new Point(12, 50));
|
|
};
|