// this file includes changes just to deactivate/hide some // stuff and functions we don't need. IDE_Morph.prototype.buildPanes = function () { this.createLogo(); this.createControlBar(); this.createCategories(); this.createPalette(); this.createStage(); this.createSpriteBar(); this.createSpriteEditor(); this.createCorralBar(); this.createCorral(); this.corral.isVisible = false; this.corralBar.isVisible= false; this.spriteBar.isVisible= false; }; IDE_Morph.prototype.createLogo = function () { var myself = this; if (this.logo) { this.logo.destroy(); } this.logo = new Morph(); //this.logo.texture = 'snap_logo_sm.png'; this.logo.texture = 'stitchcode/stitchcode_logo_small.png'; this.logo.drawNew = function () { this.image = newCanvas(this.extent()); var context = this.image.getContext('2d'), gradient = context.createLinearGradient( 0, 0, this.width(), 0 ); gradient.addColorStop(0, 'black'); gradient.addColorStop(0.5, myself.frameColor.toString()); context.fillStyle = MorphicPreferences.isFlat ? myself.frameColor.toString() : gradient; context.fillRect(0, 0, this.width(), this.height()); if (this.texture) { this.drawTexture(this.texture); } }; this.logo.drawCachedTexture = function () { var context = this.image.getContext('2d'); context.drawImage( this.cachedTexture, 5, Math.round((this.height() - this.cachedTexture.height) / 2) ); this.changed(); }; this.logo.mouseClickLeft = function () { myself.snapMenu(); }; this.logo.color = new Color(); this.logo.setExtent(new Point(200, 28)); // dimensions are fixed this.add(this.logo); }; // 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.setLeft(this.logo.left()); this.categories.setTop(this.logo.bottom()); } // palette this.palette.setLeft(this.logo.left()); this.palette.setTop(this.categories.bottom()); 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() )); } // corralBar this.corralBar.setLeft(this.stage.left()); this.corralBar.setTop(this.stage.bottom() + padding); this.corralBar.setWidth(this.stage.width()); // corral if (!contains(['selectSprite', 'tabEditor'], situation)) { this.corral.setPosition(this.corralBar.bottomLeft()); this.corral.setWidth(this.stage.width()); this.corral.setHeight(this.bottom() - this.corral.top()); this.corral.fixLayout(); } } Morph.prototype.trackChanges = true; this.changed(); }; IDE_Morph.prototype.setProjectName = function (string) { this.projectName = string.replace(/['"]/g, ''); // filter quotation marks this.hasChangedMedia = true; this.controlBar.updateLabel(); }; 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.createCorralBar = function () { // assumes the stage has already been created var padding = 5, newbutton, paintbutton, colors = [ this.groupColor, this.frameColor.darker(50), this.frameColor.darker(50) ]; if (this.corralBar) { this.corralBar.destroy(); } this.corralBar = new Morph(); this.corralBar.color = this.frameColor; this.corralBar.setHeight(this.logo.height()); // height is fixed //this.add(this.corralBar); // new sprite button newbutton = new PushButtonMorph( this, "addNewSprite", new SymbolMorph("turtle", 14) ); newbutton.corner = 12; newbutton.color = colors[0]; newbutton.highlightColor = colors[1]; newbutton.pressColor = colors[2]; newbutton.labelMinExtent = new Point(36, 18); newbutton.padding = 0; newbutton.labelShadowOffset = new Point(-1, -1); newbutton.labelShadowColor = colors[1]; newbutton.labelColor = this.buttonLabelColor; newbutton.contrast = this.buttonContrast; newbutton.drawNew(); newbutton.hint = "add a new Turtle sprite"; newbutton.fixLayout(); newbutton.setCenter(this.corralBar.center()); newbutton.setLeft(this.corralBar.left() + padding); this.corralBar.add(newbutton); paintbutton = new PushButtonMorph( this, "paintNewSprite", new SymbolMorph("brush", 15) ); paintbutton.corner = 12; paintbutton.color = colors[0]; paintbutton.highlightColor = colors[1]; paintbutton.pressColor = colors[2]; paintbutton.labelMinExtent = new Point(36, 18); paintbutton.padding = 0; paintbutton.labelShadowOffset = new Point(-1, -1); paintbutton.labelShadowColor = colors[1]; paintbutton.labelColor = this.buttonLabelColor; paintbutton.contrast = this.buttonContrast; paintbutton.drawNew(); paintbutton.hint = "paint a new sprite"; paintbutton.fixLayout(); paintbutton.setCenter(this.corralBar.center()); paintbutton.setLeft( this.corralBar.left() + padding + newbutton.width() + padding ); this.corralBar.add(paintbutton); }; 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(); }; }; // StageMorph user menu StageMorph.prototype.userMenu = function () { var ide = this.parentThatIsA(IDE_Morph), menu = new MenuMorph(this), shiftClicked = this.world().currentKey === 16, myself = this; if (ide && ide.isAppMode) { // menu.addItem('help', 'nop'); return menu; } //menu.addItem("edit", 'edit'); menu.addItem("show all", 'showAll'); menu.addItem( "pic...", function () { window.open(myself.fullImageClassic().toDataURL()); }, 'open a new window\nwith a picture of the stage' ); if (shiftClicked) { menu.addLine(); menu.addItem( "turn pen trails into new costume...", function () { var costume = new Costume( myself.trailsCanvas, Date.now().toString() ).copy(); ide.currentSprite.addCostume(costume); ide.currentSprite.wearCostume(costume); ide.hasChangedMedia = true; }, 'turn all pen trails and stamps\n' + 'into a new costume for the\ncurrently selected sprite', new Color(100, 0, 0) ); } return menu; }; IDE_Morph.prototype.createCategories = function () { // assumes the logo has already been created var myself = this; if (this.categories) { this.categories.destroy(); } this.categories = new Morph(); this.categories.color = this.groupColor; this.categories.silentSetWidth(this.logo.width()); // width is fixed function addCategoryButton(category) { var labelWidth = 75, colors = [ myself.frameColor, myself.frameColor.darker(50), SpriteMorph.prototype.blockColor[category] ], button; button = new ToggleButtonMorph( colors, myself, // the IDE is the target function () { myself.currentCategory = category; myself.categories.children.forEach(function (each) { each.refresh(); }); myself.refreshPalette(true); }, category[0].toUpperCase().concat(category.slice(1)), // label function () { // query return myself.currentCategory === category; }, null, // env null, // hint null, // template cache labelWidth, // minWidth true // has preview ); button.corner = 8; button.padding = 0; button.labelShadowOffset = new Point(-1, -1); button.labelShadowColor = colors[1]; button.labelColor = myself.buttonLabelColor; button.fixLayout(); button.refresh(); myself.categories.add(button); return button; } function fixCategoriesLayout() { var buttonWidth = myself.categories.children[0].width(), buttonHeight = myself.categories.children[0].height(), border = 3, rows = Math.ceil((myself.categories.children.length) / 2), xPadding = (myself.categories.width() - border - buttonWidth * 2) / 3, yPadding = 2, l = myself.categories.left(), t = myself.categories.top(), i = 0, row, col; myself.categories.children.forEach(function (button) { i += 1; row = Math.ceil(i / 2); col = 2 - (i % 2); button.setPosition(new Point( l + (col * xPadding + ((col - 1) * buttonWidth)), t + (row * yPadding + ((row - 1) * buttonHeight) + border) )); }); myself.categories.setHeight( (rows + 1) * yPadding + rows * buttonHeight + 2 * border ); } SpriteMorph.prototype.categories.forEach(function (cat) { if (!contains(['lists', 'other','sound','looks'], cat)) { addCategoryButton(cat); } }); 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); menu = new MenuMorph(this); menu.addItem('Project notes...', 'editProjectNotes'); menu.addLine(); menu.addItem('New', 'createNewProject'); menu.addItem('Open...', 'openProjectsBrowser'); menu.addItem('Save', "save"); if (shiftClicked) { menu.addItem( 'Save to disk', 'saveProjectToDisk', 'experimental - store this project\nin your downloads folder', new Color(100, 0, 0) ); } menu.addItem('Save As...', 'saveProjectsBrowser'); menu.addLine(); 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.addItem('Export stitch file', 'uploadStitches','Export stage drawing to stitch file (EXP)..'); menu.addItem( shiftClicked ? 'Export project as plain text...' : 'Export project...', function () { if (myself.projectName) { myself.exportProject(myself.projectName, shiftClicked); } else { myself.prompt('Export Project As...', function (name) { myself.exportProject(name); }, null, 'exportProject'); } }, 'show project data as XML\nin a new browser window', shiftClicked ? new Color(100, 0, 0) : null ); menu.addItem( 'Export blocks...', function () {myself.exportGlobalBlocks(); }, 'show global custom block definitions as XML\nin a new browser window' ); 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.addLine(); menu.addItem( 'Import tools', function () { myself.droppedText( myself.getURLsbeOrRelative( 'tools.xml' ), 'tools' ); }, 'load the official library of\npowerful blocks' ); 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.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( localize('Sounds') + '...', function () { var names = this.getCostumesList('Sounds'), libMenu = new MenuMorph(this, 'Import sound'); function loadSound(name) { var url = 'Sounds/' + name, audio = new Audio(); audio.src = url; audio.load(); myself.droppedAudio(audio, name); } names.forEach(function (line) { if (line.length > 0) { libMenu.addItem( line, function () {loadSound(line); } ); } }); libMenu.popup(world, pos); }, 'Select a sound from the media library' ); */ menu.popup(world, pos); };