diff options
| -rw-r--r-- | gui.js | 102 | ||||
| -rwxr-xr-x | history.txt | 13 | ||||
| -rw-r--r-- | lang-de.js | 8 | ||||
| -rwxr-xr-x | lang-pt.js | 26 | ||||
| -rw-r--r-- | locale.js | 4 | ||||
| -rw-r--r-- | morphic.js | 9 | ||||
| -rw-r--r-- | objects.js | 30 | ||||
| -rw-r--r-- | store.js | 6 | ||||
| -rw-r--r-- | threads.js | 35 |
9 files changed, 191 insertions, 42 deletions
@@ -64,11 +64,11 @@ standardSettings, Sound, BlockMorph, ToggleMorph, InputSlotDialogMorph, ScriptsMorph, isNil, SymbolMorph, BlockExportDialogMorph, BlockImportDialogMorph, SnapTranslator, localize, List, InputSlotMorph, SnapCloud, Uint8Array, HandleMorph, SVG_Costume, fontHeight, hex_sha512, -sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph*/ +sb, CommentMorph, CommandBlockMorph, BlockLabelPlaceHolderMorph, Audio*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2014-January-09'; +modules.gui = '2014-February-04'; // Declarations @@ -2212,6 +2212,16 @@ IDE_Morph.prototype.settingsMenu = function () { 'check for smooth, predictable\nanimations across computers' ); addPreference( + 'Flat line ends', + function () { + SpriteMorph.prototype.useFlatLineEnds = + !SpriteMorph.prototype.useFlatLineEnds; + }, + SpriteMorph.prototype.useFlatLineEnds, + 'uncheck for round ends of lines', + 'check for flat ends of lines' + ); + addPreference( 'Codification support', function () { StageMorph.prototype.enableCodeMapping = @@ -2233,6 +2243,8 @@ IDE_Morph.prototype.projectMenu = function () { 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); @@ -2380,9 +2392,94 @@ IDE_Morph.prototype.projectMenu = function () { '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); }; +IDE_Morph.prototype.getCostumesList = function (dirname) { + var dir, + costumes = []; + + dir = this.getURL(dirname); + dir.split('\n').forEach( + function (line) { + var startIdx = line.search(new RegExp('href="[^./?].*"')), + endIdx, + name; + + if (startIdx > 0) { + name = line.substring(startIdx + 6); + endIdx = name.search(new RegExp('"')); + name = name.substring(0, endIdx); + costumes.push(name); + } + } + ); + costumes.sort(function (x, y) { + return x < y ? -1 : 1; + }); + return costumes; +}; + // IDE_Morph menu actions IDE_Morph.prototype.aboutSnap = function () { @@ -2602,6 +2699,7 @@ IDE_Morph.prototype.newProject = function () { StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.enableCodeMapping = false; + SpriteMorph.prototype.useFlatLineEnds = false; this.setProjectName(''); this.projectNotes = ''; this.createStage(); diff --git a/history.txt b/history.txt index d2ffc1d..054387a 100755 --- a/history.txt +++ b/history.txt @@ -2070,3 +2070,16 @@ ______ * Threads: Revert pull request #295 (xhr-headers), breaks existing installations * BYOB: Fixed #292 (pulldowns loose lines when exported as library) * BYOB: Fixed #291 (readonly custom menus become non-readonly when block is edited) + +140203 +------ +* Threads: Fixed #313. “Block of sprite” now works for interpolated (“timed”) blocks and for reporters (i.e. SAY FOR, THINK FOR, GLIDE, ASK etc.) +* Morphic: replace deprecated DOM “body” references with “documentElement” + +140204 +------ +* GUI: Import costumes and backgrounds from the project menu, thanks, Brian, for the changeset! +* GUI: Import sounds from the project menu, thanks, Brian, for the changeset! +* Objects, Store, GUI: Flat line end option in the settings menu, saved with the project +* German translation update +* Objects: Enable playing sounds and notes on Firefox, thanks, Dean Brettle, for this fix!! @@ -185,7 +185,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', // optional 'last_changed': - '2014-01-09', // this, too, will appear in the Translators tab + '2014-02-04', // this, too, will appear in the Translators tab // GUI // control bar: @@ -767,6 +767,12 @@ SnapTranslator.dict.de = { 'ausschalten, um Animationen \ndynamischer auszuf\u00fchren', 'check for smooth, predictable\nanimations across computers': 'einschalten, damit Animationen\n\u00fcberall gleich laufen', + 'Flat line ends': + 'Flache Pinselstriche', + 'check for flat ends of lines': + 'einschalten f\u00fcr flache\nPinselstrichenden', + 'uncheck for round ends of lines': + 'auschalten f\u00fcr runde\nPinselstrichenden', // inputs 'with inputs': @@ -185,7 +185,7 @@ SnapTranslator.dict.pt = { 'translator_e-mail': 'mmsequeira@gmail.com', 'last_changed': - '2013-11-22', + '2014-01-12', // GUI // control bar: @@ -447,12 +447,20 @@ SnapTranslator.dict.pt = { 'se %b , então %c senão, %c', 'report %s': 'reporta %s', - 'stop block': - 'pára este guião de bloco', - 'stop script': - 'pára este guião de objecto', - 'stop all %stop': - 'pára tudo %stop', + 'stop %stopChoices': + 'pára %stopChoices', + 'all': + 'tudo', + 'this script': + 'este guião de objecto', + 'this block': + 'este guião de bloco', + 'stop %stopOthersChoices': + 'pára %stopOthersChoices', + 'all but this script': + 'todos os guiões de objecto excepto este', + 'other scripts in sprite': + 'os outros guiões deste objecto', 'pause all %pause': 'faz pausa em tudo %pause', 'run %cmdRing %inputs': @@ -950,8 +958,6 @@ SnapTranslator.dict.pt = { 'Este projecto ainda não tem\nnenhum bloco personalizado global.', 'select': 'seleccionar', - 'all': - 'todos', 'none': 'nenhum', @@ -1215,7 +1221,7 @@ SnapTranslator.dict.pt = { 'e^': 'a exponencial', - // delimiters + // delimitadores 'whitespace': 'espaços em branco', 'line': @@ -42,7 +42,7 @@ /*global modules, contains*/ -modules.locale = '2014-January-09'; +modules.locale = '2014-February-04'; // Global stuff @@ -149,7 +149,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', 'last_changed': - '2014-01-09' + '2014-02-04' }; SnapTranslator.dict.it = { @@ -1035,7 +1035,7 @@ /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, FileList, getBlurredShadowSupport*/ -var morphicVersion = '2014-January-09'; +var morphicVersion = '2014-February-03'; var modules = {}; // keep track of additional loaded modules var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug @@ -10029,13 +10029,14 @@ WorldMorph.prototype.fillPage = function () { this.worldCanvas.style.top = "0px"; pos.y = 0; } - if (document.body.scrollTop) { // scrolled down b/c of viewport scaling + if (document.documentElement.scrollTop) { + // scrolled down b/c of viewport scaling clientHeight = document.documentElement.clientHeight; } - if (document.body.scrollLeft) { // scrolled left b/c of viewport scaling + if (document.documentElement.scrollLeft) { + // scrolled left b/c of viewport scaling clientWidth = document.documentElement.clientWidth; } - if (this.worldCanvas.width !== clientWidth) { this.worldCanvas.width = clientWidth; this.setWidth(clientWidth); @@ -124,7 +124,7 @@ PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.objects = '2014-January-09'; +modules.objects = '2014-February-04'; var SpriteMorph; var StageMorph; @@ -186,6 +186,7 @@ SpriteMorph.prototype.sliderColor SpriteMorph.prototype.isCachingPrimitives = true; SpriteMorph.prototype.enableNesting = true; +SpriteMorph.prototype.useFlatLineEnds = false; SpriteMorph.prototype.highlightColor = new Color(250, 200, 130); SpriteMorph.prototype.highlightBorder = 8; @@ -2717,8 +2718,13 @@ SpriteMorph.prototype.drawLine = function (start, dest) { if (this.isDown) { context.lineWidth = this.size; context.strokeStyle = this.color.toString(); - context.lineCap = 'round'; - context.lineJoin = 'round'; + if (this.useFlatLineEnds) { + context.lineCap = 'butt'; + context.lineJoin = 'miter'; + } else { + context.lineCap = 'round'; + context.lineJoin = 'round'; + } context.beginPath(); context.moveTo(from.x, from.y); context.lineTo(to.x, to.y); @@ -5647,17 +5653,21 @@ Note.prototype.setupContext = function () { if (this.audioContext) { return; } var AudioContext = (function () { // cross browser some day? - return window.AudioContext || + var ctx = window.AudioContext || window.mozAudioContext || window.msAudioContext || window.oAudioContext || window.webkitAudioContext; + if (!ctx.prototype.hasOwnProperty('createGain')) { + ctx.prototype.createGain = ctx.prototype.createGainNode; + } + return ctx; }()); if (!AudioContext) { throw new Error('Web Audio API is not supported\nin this browser'); } Note.prototype.audioContext = new AudioContext(); - Note.prototype.gainNode = Note.prototype.audioContext.createGainNode(); + Note.prototype.gainNode = Note.prototype.audioContext.createGain(); Note.prototype.gainNode.gain.value = 0.25; // reduce volume by 1/4 }; @@ -5665,17 +5675,23 @@ Note.prototype.setupContext = function () { Note.prototype.play = function () { this.oscillator = this.audioContext.createOscillator(); + if (!this.oscillator.start) { + this.oscillator.start = this.oscillator.noteOn; + } + if (!this.oscillator.stop) { + this.oscillator.stop = this.oscillator.noteOff; + } this.oscillator.type = 0; this.oscillator.frequency.value = Math.pow(2, (this.pitch - 69) / 12) * 440; this.oscillator.connect(this.gainNode); this.gainNode.connect(this.audioContext.destination); - this.oscillator.noteOn(0); // deprecated, renamed to start() + this.oscillator.start(0); }; Note.prototype.stop = function () { if (this.oscillator) { - this.oscillator.noteOff(0); // deprecated, renamed to stop() + this.oscillator.stop(0); this.oscillator = null; } }; @@ -61,7 +61,7 @@ SyntaxElementMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2014-January-09'; +modules.store = '2014-February-04'; // XML_Serializer /////////////////////////////////////////////////////// @@ -378,6 +378,8 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode) { } project.stage.setTempo(model.stage.attributes.tempo); project.stage.setExtent(StageMorph.prototype.dimensions); + SpriteMorph.prototype.useFlatLineEnds = + model.stage.attributes.lines === 'flat'; project.stage.isThreadSafe = model.stage.attributes.threadsafe === 'true'; StageMorph.prototype.enableCodeMapping = @@ -1340,6 +1342,7 @@ StageMorph.prototype.toXML = function (serializer) { '<notes>$</notes>' + '<thumbnail>$</thumbnail>' + '<stage name="@" costume="@" tempo="@" threadsafe="@" ' + + 'lines="@" ' + 'codify="@" ' + 'scheduled="@" ~>' + '<pentrails>$</pentrails>' + @@ -1364,6 +1367,7 @@ StageMorph.prototype.toXML = function (serializer) { this.getCostumeIdx(), this.getTempo(), this.isThreadSafe, + SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round', this.enableCodeMapping, StageMorph.prototype.frameRate !== 0, this.trailsCanvas.toDataURL('image/png'), @@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/ // Global stuff //////////////////////////////////////////////////////// -modules.threads = '2014-January-10'; +modules.threads = '2014-Feb-03'; var ThreadManager; var Process; @@ -1643,15 +1643,15 @@ Process.prototype.doGlide = function (secs, endX, endY) { if (!this.context.startTime) { this.context.startTime = Date.now(); this.context.startValue = new Point( - this.homeContext.receiver.xPosition(), - this.homeContext.receiver.yPosition() + this.blockReceiver().xPosition(), + this.blockReceiver().yPosition() ); } if ((Date.now() - this.context.startTime) >= (secs * 1000)) { - this.homeContext.receiver.gotoXY(endX, endY); + this.blockReceiver().gotoXY(endX, endY); return null; } - this.homeContext.receiver.glide( + this.blockReceiver().glide( secs * 1000, endX, endY, @@ -1666,10 +1666,10 @@ Process.prototype.doGlide = function (secs, endX, endY) { Process.prototype.doSayFor = function (data, secs) { if (!this.context.startTime) { this.context.startTime = Date.now(); - this.homeContext.receiver.bubble(data); + this.blockReceiver().bubble(data); } if ((Date.now() - this.context.startTime) >= (secs * 1000)) { - this.homeContext.receiver.stopTalking(); + this.blockReceiver().stopTalking(); return null; } this.pushContext('doYield'); @@ -1679,16 +1679,21 @@ Process.prototype.doSayFor = function (data, secs) { Process.prototype.doThinkFor = function (data, secs) { if (!this.context.startTime) { this.context.startTime = Date.now(); - this.homeContext.receiver.doThink(data); + this.blockReceiver().doThink(data); } if ((Date.now() - this.context.startTime) >= (secs * 1000)) { - this.homeContext.receiver.stopTalking(); + this.blockReceiver().stopTalking(); return null; } this.pushContext('doYield'); this.pushContext(); }; +Process.prototype.blockReceiver = function () { + return this.context ? this.context.receiver || this.homeContext.receiver + : this.homeContext.receiver; +}; + // Process sound primitives (interpolated) Process.prototype.doPlaySoundUntilDone = function (name) { @@ -1723,7 +1728,7 @@ Process.prototype.doStopAllSounds = function () { Process.prototype.doAsk = function (data) { var stage = this.homeContext.receiver.parentThatIsA(StageMorph), - isStage = this.homeContext.receiver instanceof StageMorph, + isStage = this.blockReceiver() instanceof StageMorph, activePrompter; if (!this.prompter) { @@ -1733,7 +1738,7 @@ Process.prototype.doAsk = function (data) { ); if (!activePrompter) { if (!isStage) { - this.homeContext.receiver.bubble(data, false, true); + this.blockReceiver().bubble(data, false, true); } this.prompter = new StagePrompterMorph(isStage ? data : null); if (stage.scale < 1) { @@ -1753,7 +1758,7 @@ Process.prototype.doAsk = function (data) { stage.lastAnswer = this.prompter.inputField.getValue(); this.prompter.destroy(); this.prompter = null; - if (!isStage) {this.homeContext.receiver.stopTalking(); } + if (!isStage) {this.blockReceiver().stopTalking(); } return null; } } @@ -2288,7 +2293,7 @@ Process.prototype.createClone = function (name) { // Process sensing primitives Process.prototype.reportTouchingObject = function (name) { - var thisObj = this.homeContext.receiver; + var thisObj = this.blockReceiver(); if (thisObj) { return this.objectTouchingObject(thisObj, name); @@ -2384,7 +2389,7 @@ Process.prototype.reportColorIsTouchingColor = function (color1, color2) { }; Process.prototype.reportDistanceTo = function (name) { - var thisObj = this.homeContext.receiver, + var thisObj = this.blockReceiver(), thatObj, stage, rc, @@ -2407,7 +2412,7 @@ Process.prototype.reportDistanceTo = function (name) { }; Process.prototype.reportAttributeOf = function (attribute, name) { - var thisObj = this.homeContext.receiver, + var thisObj = this.blockReceiver(), thatObj, stage; |
