// 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; }; 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('/'); } }; // 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(); }; // 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.createStage(); this.createSpriteBar(); this.createSpriteEditor(); //this.createCorralBar(); //this.createCorral(); this.createStatusDisplay(); this.createStageHandle(); this.createPaletteHandle(); }; IDE_Morph.prototype.origSetStageExtent = IDE_Morph.prototype.setStageExtent; IDE_Morph.prototype.setStageExtent = function (aPoint) { this.origSetStageExtent(aPoint); }; IDE_Morph.prototype.origNewProject = IDE_Morph.prototype.newProject; IDE_Morph.prototype.newProject = function () { this.origNewProject(); this.stage.reRender(); this.createStatusDisplay(); }; 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.createStatusDisplay(); 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, 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); //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 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.drawNew(); // 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.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; // 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.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) ); [stageSizeButton, appModeButton].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); 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.refreshSlider(); this.updateLabel(); }; this.controlBar.refreshSlider = function () { if (Process.prototype.enableSingleStepping && !myself.isAppMode) { slider.drawNew(); 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.drawNew(); this.add(this.label); this.label.setCenter(this.center()); this.label.setLeft(this.settingsButton.right() + padding); }; }; 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.largeStageSizeButton, this.spriteEditor, //this.paletteHandle, this.stageHandle, 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 }; // 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.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; var space = new Morph(); space.alpha = 0; space.newLines = 0.5; elements.push(space); elements.push('Total Stitches : '); element = new StringMorph(); element.update = function () { this.text = (stage.turtleShepherd.getStepCount()).toString()+ " "; }; elements.push(element); elements.push(' '); elements.push('Jumps : '); element = new StringMorph(); element.update = function () { this.text = (stage.turtleShepherd.getJumpCount()).toString()+ " "; }; elements.push(element); elements.push(' '); elements.push('Dimensions : '); element = new StringMorph(); element.update = function () { this.text = (stage.turtleShepherd.getDimensions()); }; element.newLines = 1; elements.push(element); elements.push('-'); var toogleShowStitchPointsButton = new ToggleMorph( 'checkbox', null, function () { stage.renderer.toggleStitchPoints(); }, 'Stitchpoints', function () { return stage.renderer.showingStitchPoints; }); toogleShowStitchPointsButton.columns = 4; toogleShowStitchPointsButton.newColumn = 1; elements.push(toogleShowStitchPointsButton); var toogleShowJumpLinesButton = new ToggleMorph( 'checkbox', null, function () { stage.renderer.toggleJumpLines(); }, 'Jumps', function () { return stage.renderer.showingJumpLines; }); toogleShowJumpLinesButton.columns = 4; toogleShowJumpLinesButton.newColumn = 2; elements.push(toogleShowJumpLinesButton); var toggleGridButton = new ToggleMorph( 'checkbox', null, function () { stage.scene.grid.toggle(); }, 'Grid', function () { return stage.scene.grid.visible; }); toggleGridButton.columns = 4; toggleGridButton.newColumn = 3; elements.push(toggleGridButton); var toogleTurtleButton = new ToggleMorph( 'checkbox', null, function () { stage.renderer.toggleTurtle(); }, 'Turtle', function () { return stage.renderer.showingTurtle; }); toogleTurtleButton.newLines = 2; elements.push(toogleTurtleButton); elements.push('-'); var resetCameraButton = new PushButtonMorph( null, function () { stage.camera.reset(); }, 'Reset View' ); resetCameraButton.columns = 4; resetCameraButton.newColumn = 2; elements.push(resetCameraButton); var toggleTurboButton = new ToggleMorph( 'checkbox', null, function () { myself.toggleFastTracking(); }, 'Turbo mode', function () { return stage.isFastTracked; }); toggleTurboButton.columns = 4; toggleTurboButton.newColumn = 1; elements.push(toggleTurboButton); 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()); 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() { 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 = []; 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