// Force flat design IDE_Morph.prototype.setDefaultDesign = IDE_Morph.prototype.setFlatDesign; IDE_Morph.prototype.originalInit = IDE_Morph.prototype.init; IDE_Morph.prototype.init = function(isAutoFill) { this.originalInit(); // Borders are actually just paddings, so we set the bg white to get them to be white //this.backgroundColor = new Color(255,255,255); //this.setColor(this.backgroundColor); this.padding = 1; //this.frameColor = new Color(220,220,220); } // change logo IDE_Morph.prototype.originalCreateLogo = IDE_Morph.prototype.createLogo; IDE_Morph.prototype.createLogo = function () { this.originalCreateLogo(); if (MorphicPreferences.isFlat) { this.logo.texture = 'stitchcode/stitchcode_logo_small.png'; } else { this.logo.texture = 'stitchcode/stitchcode_logo_small_black.png'; } this.logo.color = new Color(230, 230, 230); this.logo.drawNew(); } IDE_Morph.prototype.buildPanes = function () { this.createLogo(); this.createControlBar(); this.createCategories(); this.createPalette(); this.createStage(); this.createSpriteEditor(); this.createSpriteBar(); this.createStatusDisplay(); }; // add buttons IDE_Morph.prototype.createControlBar = function () { // assumes the logo has already been created var padding = 4, button, stopButton, pauseButton, startButton, projectButton, settingsButton, stageSizeButton, //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); /* button = new ToggleButtonMorph( null, //colors, myself, // the IDE is the target 'setLargeStageSize', new SymbolMorph('largeStage', 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 = this.buttonLabelColor; button.query = function(){}; button.contrast = this.buttonContrast; button.drawNew(); button.fixLayout(); button.refresh(); largeStageSizeButton = button; this.controlBar.add(largeStageSizeButton); this.controlBar.largeStageSizeButton = button; // for refreshing */ //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.drawNew(); // 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.drawNew(); // button.hint = 'app & edit\nmodes'; button.fixLayout(); button.refresh(); appModeButton = button; this.controlBar.add(appModeButton); this.controlBar.appModeButton = appModeButton; // for refreshing // upload StitchButton button = new PushButtonMorph( this, 'uploadMe', new SymbolMorph('arrowUp', 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 = this.buttonLabelColor; button.contrast = this.buttonContrast; button.drawNew(); // button.hint = 'stop\nevery-\nthing'; button.fixLayout(); upstitchButton = button; this.controlBar.add(upstitchButton); // stopButton button = new PushButtonMorph( this, 'stopAllScripts', new SymbolMorph('octagon', 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(200, 0, 0); button.contrast = this.buttonContrast; button.drawNew(); // button.hint = 'stop\nevery-\nthing'; button.fixLayout(); stopButton = button; this.controlBar.add(stopButton); //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.drawNew(); // 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.drawNew(); // button.hint = 'start green\nflag scripts'; button.fixLayout(); startButton = button; this.controlBar.add(startButton); this.controlBar.startButton = startButton; // 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.drawNew(); // 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.drawNew(); // button.hint = 'edit settings'; button.fixLayout(); settingsButton = button; this.controlBar.add(settingsButton); this.controlBar.settingsButton = settingsButton; // for menu positioning // cloudButton button = new PushButtonMorph( this, 'cloudMenu', new SymbolMorph('cloud', 11) ); 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.drawNew(); // button.hint = 'cloud operations'; button.fixLayout(); cloudButton = button; this.controlBar.add(cloudButton); this.controlBar.cloudButton = cloudButton; // for menu positioning 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) ); [upstitchButton, stageSizeButton, appModeButton].forEach( function (button) { x += padding; button.setCenter(myself.controlBar.center()); button.setLeft(x); x += button.width(); } ); settingsButton.setCenter(myself.controlBar.center()); settingsButton.setLeft(this.left()); cloudButton.setCenter(myself.controlBar.center()); cloudButton.setRight(settingsButton.left() - padding); projectButton.setCenter(myself.controlBar.center()); projectButton.setRight(cloudButton.left() - padding); this.updateLabel(); }; 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.drawNew(); this.add(this.label); this.label.setCenter(this.center()); this.label.setLeft(this.settingsButton.right() + padding); }; }; IDE_Morph.prototype.setLargeStageSize = function () { this.setStageSize(1.5); } IDE_Morph.prototype.setNormalStageSize = function () { this.setStageSize(1); } IDE_Morph.prototype.setSmallStageSize = function () { this.setStageSize(0.5); } IDE_Morph.prototype.setStageSize = function (ratio) { /* var myself = this, world = this.world(), shiftClicked = (world.currentKey === 16);*/ this.setStageExtent(new Point(480 * ratio, 360 * ratio)) /* myself.step = function () { myself.stageRatio = ratio; myself.setExtent(world.extent()); myself.controlBar.stageSizeButton.refresh(); delete myself.step; } // not working yet if (shiftClicked) { ratio = SpriteIconMorph.prototype.thumbSize.x * 3 / this.stage.dimensions.x; } */ }; IDE_Morph.prototype.uploadStitches = function () { tStitch.upload(); }; ProjectDialogMorph.prototype.getExamplesProjectList = function () { var dir, projects = []; //dir = this.ide.getURL('http://snap.berkeley.edu/snapsource/Examples/'); dir = this.ide.getURL(tStitch.getBaseURL() + '/stitchcode/examples/'); dir.split('\n').forEach( function (line) { var startIdx = line.search(new RegExp('href=".*xml"')), endIdx, name, dta; if (startIdx > 0) { endIdx = line.search(new RegExp('.xml')); name = line.substring(startIdx + 6, endIdx); dta = { name: name, thumb: null, notes: null }; projects.push(dta); console.log(dta); } } ); projects.sort(function (x, y) { return x.name < y.name ? -1 : 1; }); return projects; }; ProjectDialogMorph.prototype.setSource = function (source) { var myself = this, msg; this.source = source; //this.task === 'save' ? 'local' : source; this.srcBar.children.forEach(function (button) { button.refresh(); }); switch (this.source) { case 'cloud': msg = myself.ide.showMessage('Updating\nproject list...'); this.projectList = []; SnapCloud.getProjectList( function (projectList) { myself.installCloudProjectList(projectList); msg.destroy(); }, function (err, lbl) { msg.destroy(); myself.ide.cloudError().call(null, err, lbl); } ); return; case 'examples': this.projectList = this.getExamplesProjectList(); break; case 'local': this.projectList = this.getLocalProjectList(); break; } this.listField.destroy(); this.listField = new ListMorph( this.projectList, this.projectList.length > 0 ? function (element) { return element.name; } : null, null, 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.drawNew = InputFieldMorph.prototype.drawNew; this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; if (this.source === 'local') { this.listField.action = function (item) { var src, xml; if (item === undefined) {return; } if (myself.nameField) { myself.nameField.setContents(item.name || ''); } if (myself.task === 'open') { src = localStorage['-snap-project-' + item.name]; xml = myself.ide.serializer.parse(src); myself.notesText.text = xml.childNamed('notes').contents || ''; myself.notesText.drawNew(); myself.notesField.contents.adjustBounds(); myself.preview.texture = xml.childNamed('thumbnail').contents || null; myself.preview.cachedTexture = null; myself.preview.drawNew(); } myself.edit(); }; } else { // 'examples', 'cloud' is initialized elsewhere this.listField.action = function (item) { var src, xml; if (item === undefined) {return; } if (myself.nameField) { myself.nameField.setContents(item.name || ''); } src = myself.ide.getURL( // 'http://snap.berkeley.edu/snapsource/Examples/' + tStitch.getBaseURL() + 'stitchcode/examples/' + item.name + '.xml' ); xml = myself.ide.serializer.parse(src); myself.notesText.text = xml.childNamed('notes').contents || ''; myself.notesText.drawNew(); myself.notesField.contents.adjustBounds(); myself.preview.texture = xml.childNamed('thumbnail').contents || null; myself.preview.cachedTexture = null; myself.preview.drawNew(); myself.edit(); }; } this.body.add(this.listField); this.shareButton.hide(); this.unshareButton.hide(); if (this.source === 'local') { this.deleteButton.show(); } else { // examples this.deleteButton.hide(); } this.buttons.fixLayout(); this.fixLayout(); if (this.task === 'open') { this.clearDetails(); } }; ProjectDialogMorph.prototype.openProject = function () { var proj = this.listField.selected, src; if (!proj) {return; } this.ide.source = this.source; if (this.source === 'cloud') { this.openCloudProject(proj); } else if (this.source === 'examples') { src = this.ide.getURL(tStitch.getBaseURL() + 'stitchcode/examples/' + proj.name + '.xml'); this.ide.openProjectString(src); this.destroy(); } else { // 'local' this.ide.openProject(proj.name); this.destroy(); } }; IDE_Morph.prototype.toggleAppMode = function (appMode) { var world = this.world(), elements = [ this.logo, this.controlBar.projectButton, this.controlBar.cloudButton, this.controlBar.settingsButton, this.controlBar.stageSizeButton, this.controlBar.stageSizeButton, //this.controlBar.largeStageSizeButton, this.spriteEditor, this.palette, this.categories ]; this.isAppMode = isNil(appMode) ? !this.isAppMode : appMode; Morph.prototype.trackChanges = false; if (this.isAppMode) { this.setColor(this.appModeColor); this.controlBar.setColor(this.color); this.controlBar.appModeButton.refresh(); elements.forEach(function (e) { e.hide(); }); world.children.forEach(function (morph) { if (morph instanceof DialogBoxMorph) { morph.hide(); } }); } else { this.setColor(this.backgroundColor); this.controlBar.setColor(this.frameColor); elements.forEach(function (e) { e.show(); }); this.stage.setScale(1); // show all hidden dialogs world.children.forEach(function (morph) { if (morph instanceof DialogBoxMorph) { morph.show(); } }); // prevent scrollbars from showing when morph appears world.allChildren().filter(function (c) { return c instanceof ScrollFrameMorph; }).forEach(function (s) { s.adjustScrollBars(); }); } this.setExtent(this.world().extent()); // resume trackChanges }; IDE_Morph.prototype.createStatusDisplay = function () { var frame, padding = 1, myself = this, elements = [], beetle = this.currentSprite.beetle, 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') { element = new StringMorph(localize(element), 12, null, true); }; 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.drawNew(); 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; // Buttons and toggles var toogleShowStitchButton = new ToggleMorph( 'checkbox', null, function () { tStitch.toogleShowStitches(); }, 'Show Stitches', function () { return tStitch.getShowStitches(); }); toogleShowStitchButton.columns = 2 toogleShowStitchButton.newLines = 1; elements.push(toogleShowStitchButton); var toogleShowJumpsButton = new ToggleMorph( 'checkbox', null, function () { tStitch.toogleShowJumpStitches(); }, 'Show Jump Stitches', function () { return tStitch.getShowJumpStitches(); }); toogleShowJumpsButton.columns = 1; elements.push(toogleShowJumpsButton); elements.forEach(function(each) { myself.statusDisplay.addElement(each) }); }; // IDE_Morph layout IDE_Morph.prototype.fixLayout = function (situation) { // situation is a string, i.e. // 'selectSprite' or 'refreshPalette' or 'tabEditor' var padding = this.padding; 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.padding = this.padding; this.categories.setLeft(this.logo.left()); this.categories.setTop(this.logo.bottom()+padding); } // palette this.palette.setLeft(this.logo.left()); this.palette.setTop(this.categories.bottom() + padding); this.palette.setHeight(this.bottom() - this.palette.top()); 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 ? 0.5 : 1); this.stage.setScale(this.isSmallStage ? this.stageRatio : 1); this.stage.setTop(this.logo.bottom() + padding); this.stage.setRight(this.right()); } /* // spriteBar this.spriteBar.setPosition(this.logo.bottomRight().add(padding)); this.spriteBar.setExtent(new Point( Math.max(0, this.stage.left() - padding - this.spriteBar.left()), this.categories.bottom() - this.spriteBar.top() - padding )); this.spriteBar.fixLayout(); */ // spriteEditor if (this.spriteEditor.isVisible) { //this.spriteEditor.setPosition(this.spriteBar.bottomLeft()); this.spriteEditor.setPosition(this.logo.bottomRight().add(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() { var minX=999999999, maxX=0, minY=999999999, maxY=0; for (var i=0; imaxX) maxX = x1; if (y1maxY) maxY = y1; } var svgStr = "\n"; svgStr += "\n"; svgStr += "\n"; svgStr += "Embroidery export\n"; svgStr += "\n"; } } else { if (tStitch.stitches.jump[i-1]&& i>1) { svgStr +=" \n\n" blob = new Blob([svgStr], {type: 'text/plain;charset=utf-8'}); saveAs(blob, (this.projectName ? this.projectName : 'turtlestitch') + '.svg'); } // EXP export IDE_Morph.prototype.downloadEXP = function() { var expArr = new Array(); pixels_per_millimeter = 5 scale = 10 / pixels_per_millimeter; function move(x, y) { y *= -1; if (x<0) x = x + 256; expArr.push(x); if (y<0) y = y + 256; expArr.push(y); } for (var i=1; i 0) { libMenu.addItem( line, function () {loadCostume(line); } ); } }); libMenu.popup(world, pos); }, 'Select a costume from the media library' ); /* graphicsName = 'Costumes'; menu.addItem( localize(graphicsName) + '...', function () { var dir = graphicsName, names = myself.getCostumesList(dir), libMenu = new MenuMorph( myself, localize('Import') + ' ' + localize(dir) ); function loadCostume(name) { var url = dir + '/' + name, img = new Image(); img.onload = function () { var canvas = newCanvas(new Point(img.width, img.height)); canvas.getContext('2d').drawImage(img, 0, 0); myself.droppedImage(canvas, name); }; img.src = url; } names.forEach(function (line) { if (line.length > 0) { libMenu.addItem( line, function () {loadCostume(line); } ); } }); libMenu.popup(world, pos); }, 'Select a costume from the media library' ); */ menu.addItem( 'Libraries...', function () { // read a list of libraries from an external file, var libMenu = new MenuMorph(this, 'Import library'), libUrl = 'http://snap.berkeley.edu/snapsource/libraries/' + 'LIBRARIES'; function loadLib(name) { var url = 'http://snap.berkeley.edu/snapsource/libraries/' + name + '.xml'; myself.droppedText(myself.getURL(url), name); } myself.getURL(libUrl).split('\n').forEach(function (line) { if (line.length > 0) { libMenu.addItem( line.substring(line.indexOf('\t') + 1), function () { loadLib( line.substring(0, line.indexOf('\t')) ); } ); } }); libMenu.popup(world, pos); }, 'Select categories of additional blocks to add to this project.' ); menu.popup(world, pos); }; IDE_Morph.prototype.snapMenu = function () { var menu, world = this.world(); menu = new MenuMorph(this); menu.addItem('About...', 'aboutSnap'); menu.addLine(); menu.addItem( 'Reference manual', function () { window.open('help/SnapManual.pdf', 'SnapReferenceManual'); } ); menu.addItem( 'TurtleStich! website', function () { window.open('http://'+window.location.hostname, 'SnapWebsite'); } ); menu.addItem( 'Snap! website', function () { window.open('http://snap.berkeley.edu/', 'SnapWebsite'); } ); menu.addItem( 'Download source', function () { window.open( 'http://snap.berkeley.edu/snapsource/snap.zip', 'SnapSource' ); } ); 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); } 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.drawNew(); 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.drawNew(); 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.drawNew(); padlock.setPosition(nameField.bottomLeft().add(2)); padlock.drawNew(); 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.drawNew(); 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.drawNew(); 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.drawNew(); 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.createCorral = function () { // assumes the corral bar has already been created var frame, template, padding = 5, myself = this; if (this.corral) { this.corral.destroy(); } this.corral = new Morph(); this.corral.color = this.groupColor; //this.add(this.corral); this.corral.stageIcon = new SpriteIconMorph(this.stage); this.corral.stageIcon.isDraggable = false; this.corral.add(this.corral.stageIcon); frame = new ScrollFrameMorph(null, null, this.sliderColor); frame.acceptsDrops = false; frame.contents.acceptsDrops = false; frame.contents.wantsDropOf = function (morph) { return morph instanceof SpriteIconMorph; }; frame.contents.reactToDropOf = function (spriteIcon) { myself.corral.reactToDropOf(spriteIcon); }; frame.alpha = 0; this.sprites.asArray().forEach(function (morph) { template = new SpriteIconMorph(morph, template); frame.contents.add(template); }); this.corral.frame = frame; this.corral.add(frame); this.corral.fixLayout = function () { this.stageIcon.setCenter(this.center()); this.stageIcon.setLeft(this.left() + padding); this.frame.setLeft(this.stageIcon.right() + padding); this.frame.setExtent(new Point( this.right() - this.frame.left(), this.height() )); this.arrangeIcons(); this.refresh(); }; this.corral.arrangeIcons = function () { var x = this.frame.left(), y = this.frame.top(), max = this.frame.right(), start = this.frame.left(); this.frame.contents.children.forEach(function (icon) { var w = icon.width(); if (x + w > max) { x = start; y += icon.height(); // they're all the same } icon.setPosition(new Point(x, y)); x += w; }); this.frame.contents.adjustBounds(); }; this.corral.addSprite = function (sprite) { this.frame.contents.add(new SpriteIconMorph(sprite)); this.fixLayout(); }; this.corral.refresh = function () { this.stageIcon.refresh(); this.frame.contents.children.forEach(function (icon) { icon.refresh(); }); }; this.corral.wantsDropOf = function (morph) { return morph instanceof SpriteIconMorph; }; this.corral.reactToDropOf = function (spriteIcon) { var idx = 1, pos = spriteIcon.position(); spriteIcon.destroy(); this.frame.contents.children.forEach(function (icon) { if (pos.gt(icon.position()) || pos.y > icon.bottom()) { idx += 1; } }); myself.sprites.add(spriteIcon.object, idx); myself.createCorral(); myself.fixLayout(); }; }; ProjectDialogMorph.prototype.buildContents = function () { var thumbnail, notification; this.addBody(new Morph()); this.body.color = this.color; this.srcBar = new AlignmentMorph('column', this.padding / 2); if (this.ide.cloudMsg) { notification = new TextMorph( this.ide.cloudMsg, 10, null, // style false, // bold null, // italic null, // alignment null, // width null, // font name new Point(1, 1), // shadow offset new Color(255, 255, 255) // shadowColor ); notification.refresh = nop; this.srcBar.add(notification); } //disable cloud for now // this.addSourceButton('cloud', localize('Cloud'), 'cloud'); this.addSourceButton('local', localize('Browser'), 'storage'); if (this.task === 'open') { this.addSourceButton('examples', localize('Examples'), 'poster'); } this.srcBar.fixLayout(); this.body.add(this.srcBar); if (this.task === 'save') { this.nameField = new InputFieldMorph(this.ide.projectName); this.body.add(this.nameField); } this.listField = new ListMorph([]); 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.drawNew = InputFieldMorph.prototype.drawNew; this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; this.body.add(this.listField); this.preview = new Morph(); this.preview.fixLayout = nop; this.preview.edge = InputFieldMorph.prototype.edge; this.preview.fontSize = InputFieldMorph.prototype.fontSize; this.preview.typeInPadding = InputFieldMorph.prototype.typeInPadding; this.preview.contrast = InputFieldMorph.prototype.contrast; this.preview.drawNew = function () { InputFieldMorph.prototype.drawNew.call(this); if (this.texture) { this.drawTexture(this.texture); } }; this.preview.drawCachedTexture = function () { var context = this.image.getContext('2d'); context.drawImage(this.cachedTexture, this.edge, this.edge); this.changed(); }; this.preview.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; this.preview.setExtent( this.ide.serializer.thumbnailSize.add(this.preview.edge * 2) ); this.body.add(this.preview); this.preview.drawNew(); if (this.task === 'save') { thumbnail = this.ide.stage.thumbnail( SnapSerializer.prototype.thumbnailSize ); this.preview.texture = null; this.preview.cachedTexture = thumbnail; this.preview.drawCachedTexture(); } this.notesField = new ScrollFrameMorph(); this.notesField.fixLayout = nop; this.notesField.edge = InputFieldMorph.prototype.edge; this.notesField.fontSize = InputFieldMorph.prototype.fontSize; this.notesField.typeInPadding = InputFieldMorph.prototype.typeInPadding; this.notesField.contrast = InputFieldMorph.prototype.contrast; this.notesField.drawNew = InputFieldMorph.prototype.drawNew; this.notesField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder; this.notesField.acceptsDrops = false; this.notesField.contents.acceptsDrops = false; if (this.task === 'open') { this.notesText = new TextMorph(''); } else { // 'save' this.notesText = new TextMorph(this.ide.projectNotes); this.notesText.isEditable = true; this.notesText.enableSelecting(); } this.notesField.isTextLineWrapping = true; this.notesField.padding = 3; this.notesField.setContents(this.notesText); this.notesField.setWidth(this.preview.width()); this.body.add(this.notesField); if (this.task === 'open') { this.addButton('openProject', 'Open'); this.action = 'openProject'; } else { // 'save' this.addButton('saveProject', 'Save'); this.action = 'saveProject'; } this.shareButton = this.addButton('shareProject', 'Share'); this.unshareButton = this.addButton('unshareProject', 'Unshare'); this.shareButton.hide(); this.unshareButton.hide(); this.deleteButton = this.addButton('deleteProject', 'Delete'); this.addButton('cancel', 'Cancel'); if (notification) { this.setExtent(new Point(455, 335).add(notification.extent())); } else { this.setExtent(new Point(455, 335)); } this.fixLayout(); }; IDE_Morph.prototype.droppedImageStage = function (aCanvas, name) { var costume = new Costume( aCanvas, this.currentSprite.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.stage.addCostume(costume); this.stage.wearCostume(costume); //this.spriteBar.tabBar.tabTo('costumes'); this.hasChangedMedia = true; };