diff options
| author | Michael Ball <cycomachead@gmail.com> | 2014-02-04 11:59:45 -0800 |
|---|---|---|
| committer | Michael Ball <cycomachead@gmail.com> | 2014-02-04 11:59:45 -0800 |
| commit | 817f4c5420e5d55409c88386c478f14e4735a627 (patch) | |
| tree | 29af845c58934508a0ea842786c5838e8deb4519 | |
| parent | 9aa3921dd04ee8b6fedec0116f9e3f5503e4043b (diff) | |
| parent | 8b5fa2ff9bd81ad9227b2593f9ccd6fdb8d32444 (diff) | |
| download | snap-817f4c5420e5d55409c88386c478f14e4735a627.tar.gz snap-817f4c5420e5d55409c88386c478f14e4735a627.zip | |
resolve merge conflicts; date problems only
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | blocks.js | 41 | ||||
| -rw-r--r-- | byob.js | 10 | ||||
| -rw-r--r-- | cloud.js | 7 | ||||
| -rw-r--r-- | gui.js | 106 | ||||
| -rwxr-xr-x | history.txt | 41 | ||||
| -rw-r--r-- | lang-de.js | 32 | ||||
| -rw-r--r-- | lang-fr.js | 6 | ||||
| -rwxr-xr-x | lang-pt.js | 26 | ||||
| -rw-r--r-- | libraries/LIBRARIES | 5 | ||||
| -rw-r--r-- | libraries/iteration-composition.xml | 1 | ||||
| -rw-r--r-- | libraries/list-utilities.xml | 1 | ||||
| -rw-r--r-- | libraries/stream-tools.xml | 1 | ||||
| -rw-r--r-- | libraries/variadic-reporters.xml | 1 | ||||
| -rw-r--r-- | libraries/word-sentence.xml | 1 | ||||
| -rw-r--r-- | lists.js | 4 | ||||
| -rw-r--r-- | locale.js | 10 | ||||
| -rw-r--r-- | morphic.js | 13 | ||||
| -rw-r--r-- | objects.js | 97 | ||||
| -rw-r--r-- | paint.js | 1430 | ||||
| -rw-r--r-- | store.js | 8 | ||||
| -rw-r--r-- | threads.js | 106 | ||||
| -rw-r--r-- | widgets.js | 4 | ||||
| -rw-r--r-- | xml.js | 36 |
24 files changed, 1168 insertions, 821 deletions
@@ -9,7 +9,7 @@ inspired by Scratch written by Jens Mönig and Brian Harvey jens@moenig.org, bh@cs.berkeley.edu -Copyright (C) 2013 by Jens Mönig and Brian Harvey +Copyright (C) 2014 by Jens Mönig and Brian Harvey Snap! is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -155,7 +155,8 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2013-December-27'; +modules.blocks = '2014-February-04'; + var SyntaxElementMorph; var BlockMorph; @@ -1014,7 +1015,6 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { 'attributesMenu', true ); - part.isStatic = true; break; case '%fun': part = new InputSlotMorph( @@ -1056,6 +1056,33 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { ); part.setContents(['encode URI']); break; + case '%stopChoices': + part = new InputSlotMorph( + null, + false, + { + 'all' : ['all'], + 'this script' : ['this script'], + 'this block' : ['this block'] + }, + true + ); + part.setContents(['all']); + part.isStatic = true; + break; + case '%stopOthersChoices': + part = new InputSlotMorph( + null, + false, + { + 'all but this script' : ['all but this script'], + 'other scripts in sprite' : ['other scripts in sprite'] + }, + true + ); + part.setContents(['all but this script']); + part.isStatic = true; + break; case '%typ': part = new InputSlotMorph( null, @@ -3284,6 +3311,7 @@ CommandBlockMorph.prototype.snap = function () { CommandBlockMorph.prototype.isStop = function () { return ([ + 'doStopThis', 'doStop', 'doStopBlock', 'doStopAll', @@ -6319,6 +6347,8 @@ InputSlotMorph.prototype.dropDownMenu = function () { if (Object.prototype.hasOwnProperty.call(choices, key)) { if (key[0] === '~') { menu.addLine(); + // } else if (key.indexOf('§_def') === 0) { + // menu.addItem(choices[key].blockInstance(), choices[key]); } else { menu.addItem(key, choices[key]); } @@ -6535,6 +6565,11 @@ InputSlotMorph.prototype.attributesMenu = function () { dict[name] = name; }); } + /* + obj.customBlocks.forEach(function (def, i) { + dict['§_def' + i] = def + }); + */ return dict; }; @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -106,7 +106,7 @@ SymbolMorph, isNil*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2013-November-26'; +modules.byob = '2014-January-10'; // Declarations @@ -194,7 +194,7 @@ CustomBlockDefinition.prototype.prototypeInstance = function () { part.fragment.type = slot[0]; part.fragment.defaultValue = slot[1]; part.fragment.options = slot[2]; - part.fragment.isReadonly = slot[3] || false; + part.fragment.isReadOnly = slot[3] || false; } } }); @@ -3189,13 +3189,13 @@ BlockExportDialogMorph.prototype.selectNone = function () { BlockExportDialogMorph.prototype.exportBlocks = function () { var str = this.serializer.serialize(this.blocks); if (this.blocks.length > 0) { - window.open('data:text/xml,<blocks app="' + window.open(encodeURI('data:text/xml,<blocks app="' + this.serializer.app + '" version="' + this.serializer.version + '">' + str - + '</blocks>'); + + '</blocks>')); } else { new DialogBoxMorph().inform( 'Export blocks', @@ -6,7 +6,7 @@ written by Jens Mönig - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -29,7 +29,7 @@ /*global modules, IDE_Morph, SnapSerializer, hex_sha512, alert, nop*/ -modules.cloud = '2013-November-26'; +modules.cloud = '2014-January-09'; // Global stuff @@ -37,9 +37,6 @@ var Cloud; var SnapCloud = new Cloud( 'https://snapcloud.miosoft.com/miocon/app/login?_app=SnapCloud' - //'192.168.2.110:8087/miocon/app/login?_app=SnapCloud' - //'192.168.186.146:8087/miocon/app/login?_app=SnapCloud' - // 'localhost/miocon/app/login?_app=SnapCloud' ); // Cloud ///////////////////////////////////////////////////////////// @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -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 = '2013-November-07'; +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 () { @@ -2391,7 +2488,7 @@ IDE_Morph.prototype.aboutSnap = function () { world = this.world(); aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n--- beta ---\n\n' - + 'Copyright \u24B8 2013 Jens M\u00F6nig and ' + + 'Copyright \u24B8 2014 Jens M\u00F6nig and ' + 'Brian Harvey\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n' @@ -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 642ea7f..77c2e9d 100755 --- a/history.txt +++ b/history.txt @@ -2044,3 +2044,44 @@ ______ ------ * Objects: stage watchers for „mouse x“ and „mouse y“ sensing reporters. Thanks, Michael! * Store: fixed saving/loading/localisation of new mouse coordinate stage watchers + +140108 +------ +* Threads, Blocks, Objects: The FOR reporter’s first input now also accepts blocks and scripts („rings“), and reports a copy that is bound to the sprite indicated by the second input. This lets you „zombify“ (or remote-control) sprites (and create custom TELL and ASK blocks) +* Blocks: initial support for „sensing“ sprite-only custom block definitions, commented out for now +* Paint: Add mouseLeaveDragging() event behavior, thanks, Kartik, for this fix! +* Objects: Only shrink-wrap sprite costumes, thanks, Kartik, for this fix! +* Threads: Added xhr-headers to HTTP block, thanks, Tim! +* Threads, Blocks, Objects: Added StopOthers primitive, thanks, Kartik! +* Added „all but this option“ to StopOthers primitive, fixed the implementation +* Updated German translation with new strings + +140109 +------ +* Objects: Mechanism for migrating blocks in existing projects to newer versions +* Blocks, Objects, Threads: Collapse old STOP primitives into a single one with a dropdown of options +* German translation update for new (migrated) STOP block +* Morphic: Fixed updateReferences() (how could nobody notice so long?!) +* XML: resolved unexpected assignment expressions (conform to the latest JSLint quibbles) +* validated all source files against the latest JSLint version + +140110 +------ +* 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!! +* Update Portuguese translation, thanks, Manuel! +* Update French translation, thanks, grego! @@ -6,7 +6,7 @@ written by Jens Mönig - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -185,7 +185,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', // optional 'last_changed': - '2013-10-04', // this, too, will appear in the Translators tab + '2014-02-04', // this, too, will appear in the Translators tab // GUI // control bar: @@ -447,12 +447,20 @@ SnapTranslator.dict.de = { 'falls %b %c sonst %c', 'report %s': 'berichte %s', - 'stop block': - 'stoppe diesen Block', - 'stop script': - 'stoppe dieses Skript', - 'stop all %stop': - 'stoppe alles %stop', + 'stop %stopChoices': + 'stoppe %stopChoices', + 'all': + 'alles', + 'this script': + 'dieses Skript', + 'this block': + 'diesen Block', + 'stop %stopOthersChoices': + 'stoppe %stopOthersChoices', + 'all but this script': + 'alles au\u00dfer diesem Skript', + 'other scripts in sprite': + 'andere Skripte in diesem Objekt', 'pause all %pause': 'pausiere alles %pause', 'run %cmdRing %inputs': @@ -759,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': @@ -950,8 +964,6 @@ SnapTranslator.dict.de = { 'in diesem Projekt gibt es noch keine\nglobalen Bl\u00f6cke', 'select': 'ausw\u00e4hlen', - 'all': - 'alles', 'none': 'nichts', @@ -185,7 +185,7 @@ SnapTranslator.dict.fr = { 'translator_e-mail': 'i.scool@mac.com', // optional 'last_changed': - '2013-12-04', // this, too, will appear in the Translators tab + '2014-02-04', // this, too, will appear in the Translators tab // GUI // control bar: @@ -469,7 +469,9 @@ SnapTranslator.dict.fr = { 'moi-m\u00EAme', 'delete this clone': 'supprime ce clone', - + 'pause all': + 'mettre en pause', + // sensing: 'touching %col ?': ' %col touch\u00E9?', @@ -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': diff --git a/libraries/LIBRARIES b/libraries/LIBRARIES new file mode 100644 index 0000000..f11aa85 --- /dev/null +++ b/libraries/LIBRARIES @@ -0,0 +1,5 @@ +iteration-composition Iteration, composition +list-utilities List utilities +stream-tools Streams (lazy lists) +variadic-reporters Variadic reporters +word-sentence Words, sentences diff --git a/libraries/iteration-composition.xml b/libraries/iteration-composition.xml new file mode 100644 index 0000000..0f16bb6 --- /dev/null +++ b/libraries/iteration-composition.xml @@ -0,0 +1 @@ +<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="cascade %'num' times %'function' %'init' %'#'" type="reporter" category="control"><comment w="138" collapsed="false">Call f(f(f(...(f(x))))) n times where the three input slots are n, f, and x from left to right. The # variable can be used inside f to represent how many times f has been called.</comment><code></code><inputs><input type="%n"></input><input type="%repRing"></input><input type="%s"></input><input type="%upvar"></input></inputs><script><block s="doDeclareVariables"><list><l>result</l></list></block><block s="doSetVar"><l>result</l><block var="init"/></block><block s="doSetVar"><l>#</l><l>0</l></block><block s="doRepeat"><block var="num"/><script><block s="doChangeVar"><l>#</l><l>1</l></block><block s="doSetVar"><l>result</l><block s="evaluate"><block var="function"/><list><block var="result"/></list></block></block></script></block><block s="doReport"><block var="result"/></block></script></block-definition><block-definition s="cascade until %'pred' %'function' %'init' %'#'" type="reporter" category="control"><comment w="90" collapsed="false">Call f(f(f(...(f(x))))) until condition is true, where the three input slots are condition, f, and x from left to right. The # variable can be used inside f or condition to indicate how many times f has been called.</comment><code></code><inputs><input type="%predRing"></input><input type="%repRing"></input><input type="%s"></input><input type="%upvar"></input></inputs><script><block s="doDeclareVariables"><list><l>result</l></list></block><block s="doSetVar"><l>result</l><block var="init"/></block><block s="doSetVar"><l>#</l><l>0</l></block><block s="doUntil"><block s="evaluate"><block var="pred"/><list><block var="result"/></list></block><script><block s="doChangeVar"><l>#</l><l>1</l></block><block s="doSetVar"><l>result</l><block s="evaluate"><block var="function"/><list><block var="result"/></list></block></block></script></block><block s="doReport"><block var="result"/></block></script></block-definition><block-definition s="compose %'f' %'g'" type="reporter" category="control"><comment w="90" collapsed="false">Returns the function f(g(x)) where f and g are the two inputs.</comment><code></code><inputs><input type="%repRing"></input><input type="%repRing"></input></inputs><script><block s="doReport"><block s="reifyReporter"><autolambda><block s="evaluate"><block var="f"/><list><block s="evaluate"><block var="g"/><list><l></l></list></block></list></block></autolambda><list></list></block></block></script></block-definition><block-definition s="repeat %'action' until %'pred'" type="command" category="control"><comment w="90" collapsed="false">Like the built-in REPEAT UNTIL block, except that the ending condition is not tested until the script has been run the first time. So the script is run at least once.</comment><code></code><inputs><input type="%cs"></input><input type="%boolUE"></input></inputs><script><block s="doRun"><block var="action"/><list></list></block><block s="doUntil"><block s="evaluate"><block var="pred"/><list></list></block><script><block s="doRun"><block var="action"/><list></list></block></script></block></script></block-definition><block-definition s="repeat %'action' while %'pred'" type="command" category="control"><comment w="90" collapsed="false">Run the script repeatedly, as long as the given condition is true. Runs the script at least once before testing the condition.</comment><code></code><inputs><input type="%cs"></input><input type="%boolUE"></input></inputs><script><block s="doRun"><block var="action"/><list></list></block><block s="doUntil"><block s="reportNot"><block s="evaluate"><block var="pred"/><list></list></block></block><script><block s="doRun"><block var="action"/><list></list></block></script></block></script></block-definition><block-definition s="repeat while %'pred' %'action'" type="command" category="control"><comment w="90" collapsed="false">Runs the script repeatedly, as long as the condition is true. Tests the condition before the first time the script is run. Like the built in REPEAT UNTIL except that in this block the condition must be true, not false.</comment><code></code><inputs><input type="%boolUE"></input><input type="%cs"></input></inputs><script><block s="doUntil"><block s="reportNot"><block s="evaluate"><block var="pred"/><list></list></block></block><script><block s="doRun"><block var="action"/><list></list></block></script></block></script></block-definition><block-definition s="repeat %'num' %'#' %'action'" type="command" category="control"><comment w="171" collapsed="false">Runs the script the specified number of times, like the built-in REPEAT block, but this one provides the # variable that can be used inside the script. Try
REPEAT (200)
 MOVE (#) STEPS
 RIGHT 92
with the pen down.</comment><code></code><inputs><input type="%n"></input><input type="%upvar"></input><input type="%cs"></input></inputs><script><block s="doSetVar"><l>#</l><l>0</l></block><block s="doRepeat"><block var="num"/><script><block s="doChangeVar"><l>#</l><l>1</l></block><block s="doRun"><block var="action"/><list></list></block></script></block></script></block-definition></blocks>
\ No newline at end of file diff --git a/libraries/list-utilities.xml b/libraries/list-utilities.xml new file mode 100644 index 0000000..dc7ee75 --- /dev/null +++ b/libraries/list-utilities.xml @@ -0,0 +1 @@ +<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="append %'lists'" type="reporter" category="lists"><comment x="0" y="0" w="287" collapsed="false">Take any number of input lists, and create a new list containing the items of the input lists. So
 APPEND [A B] [C D]
where the [,,,] are lists reports the list
 [A B C D]
not [[A B] [C D]].</comment><header></header><code></code><inputs><input type="%mult%l"></input></inputs><script><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block var="lists"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportListLength"><block var="lists"/></block><l>1</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block var="lists"/></block></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportListItem"><l>1</l><block var="lists"/></block><block s="reportNewList"><list></list></block></block><script><block s="doReport"><custom-block s="append %mult%l"><block s="reportCDR"><block var="lists"/></block></custom-block></block></script></block><block s="doReport"><block s="reportCONS"><block s="reportListItem"><l>1</l><block s="reportListItem"><l>1</l><block var="lists"/></block></block><custom-block s="append %mult%l"><block s="reportCONS"><block s="reportCDR"><block s="reportListItem"><l>1</l><block var="lists"/></block></block><block s="reportCDR"><block var="lists"/></block></block></custom-block></block></block></script></block></script></block-definition><block-definition s="reverse %'data'" type="reporter" category="lists"><comment x="0" y="0" w="223" collapsed="false">Reports a new list containing the items of the input list, but in the opposite order.</comment><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doDeclareVariables"><list><l>helper</l></list></block><block s="doSetVar"><l>helper</l><block s="reifyScript"><script><block s="doIf"><block s="reportEquals"><block var="input"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block var="result"/></block></script></block><block s="doReport"><block s="evaluate"><block var="helper"/><list><block s="reportCDR"><block var="input"/></block><block s="reportCONS"><block s="reportListItem"><l>1</l><block var="input"/></block><block var="result"/></block></list></block></block></script><list><l>input</l><l>result</l></list></block></block><block s="doWarp"><script><block s="doReport"><block s="evaluate"><block var="helper"/><list><block var="data"/><block s="reportNewList"><list></list></block></list></block></block></script></block></script></block-definition><block-definition s="remove duplicates from %'data'" type="reporter" category="lists"><comment x="0" y="0" w="209" collapsed="false">Reports a new list whose items are the same as in the input list, except that if two or more equal items appear in the input list, only the last one is kept in the result.</comment><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block var="data"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doIfElse"><block s="reportListContainsItem"><block s="reportCDR"><block var="data"/></block><block s="reportListItem"><l>1</l><block var="data"/></block></block><script><block s="doReport"><custom-block s="remove duplicates from %l"><block s="reportCDR"><block var="data"/></block></custom-block></block></script><script><block s="doReport"><block s="reportCONS"><block s="reportListItem"><l>1</l><block var="data"/></block><custom-block s="remove duplicates from %l"><block s="reportCDR"><block var="data"/></block></custom-block></block></block></script></block></script></block></script></block-definition><block-definition s="sort %'data' ordering with %'function'" type="reporter" category="lists"><comment w="204" collapsed="false">Reports a sorted version of the list in its first input slot, using the comparison function in the second input slot. For a list of numbers, using < as the comparison function will sort from low to high; using > will sort from high to low.</comment><header></header><code></code><inputs><input type="%l"></input><input type="%predRing"></input></inputs><script><block s="doDeclareVariables"><list><l>even items</l><l>odd items</l><l>merge</l></list></block><block s="doSetVar"><l>odd items</l><block s="reifyScript"><script><block s="doIf"><block s="reportEquals"><l></l><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><block s="reportCONS"><block s="reportListItem"><l>1</l><l/></block><block s="evaluate"><block var="even items"/><list><block s="reportCDR"><l/></block></list></block></block></block></script><list></list></block></block><block s="doSetVar"><l>even items</l><block s="reifyScript"><script><block s="doIf"><block s="reportEquals"><l></l><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><block s="evaluate"><block var="odd items"/><list><block s="reportCDR"><l/></block></list></block></block></script><list></list></block></block><block s="doSetVar"><l>merge</l><block s="reifyScript"><script><block s="doIf"><block s="reportEquals"><block var="#1"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block var="#2"/></block></script></block><block s="doIf"><block s="reportEquals"><block var="#2"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block var="#1"/></block></script></block><block s="doIfElse"><block s="evaluate"><block var="function"/><list><block s="reportListItem"><l>1</l><block var="#1"/></block><block s="reportListItem"><l>1</l><block var="#2"/></block></list></block><script><block s="doReport"><block s="reportCONS"><block s="reportListItem"><l>1</l><block var="#1"/></block><block s="evaluate"><block var="merge"/><list><block s="reportCDR"><block var="#1"/></block><block var="#2"/></list></block></block></block></script><script><block s="doReport"><block s="reportCONS"><block s="reportListItem"><l>1</l><block var="#2"/></block><block s="evaluate"><block var="merge"/><list><block var="#1"/><block s="reportCDR"><block var="#2"/></block></list></block></block></block></script></block></script><list><l>#1</l><l>#2</l></list></block></block><block s="doIf"><block s="reportEquals"><block var="data"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportCDR"><block var="data"/></block><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block var="data"/></block></script></block><block s="doReport"><block s="evaluate"><block var="merge"/><list><custom-block s="sort %l ordering with %predRing"><block s="evaluate"><block var="odd items"/><list><block var="data"/></list></block><block var="function"/></custom-block><custom-block s="sort %l ordering with %predRing"><block s="evaluate"><block var="even items"/><list><block var="data"/></list></block><block var="function"/></custom-block></list></block></block></script></block-definition></blocks>
\ No newline at end of file diff --git a/libraries/stream-tools.xml b/libraries/stream-tools.xml new file mode 100644 index 0000000..66efcec --- /dev/null +++ b/libraries/stream-tools.xml @@ -0,0 +1 @@ +<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="%'head' in front of stream %'tail'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%s"></input><input type="%anyUE"></input></inputs><script><block s="doReport"><block s="reportNewList"><list><block var="head"/><block var="tail"/><block s="reportFalse"></block><block s="reportFalse"></block></list></block></block></script></block-definition><block-definition s="head of stream %'stream'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doReport"><block s="reportListItem"><l>1</l><block var="stream"/></block></block></script></block-definition><block-definition s="tail of stream %'stream'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doWarp"><script><block s="doIf"><block s="reportListItem"><l>3</l><block var="stream"/></block><script><block s="doReport"><block s="reportListItem"><l>4</l><block var="stream"/></block></block></script></block><block s="doReplaceInList"><l>4</l><block var="stream"/><block s="evaluate"><block s="reportListItem"><l>2</l><block var="stream"/></block><list></list></block></block><block s="doReplaceInList"><l>3</l><block var="stream"/><block s="reportTrue"></block></block><block s="doReport"><block s="reportListItem"><l>4</l><block var="stream"/></block></block></script></block></script></block-definition><block-definition s="map %'function' over stream %'stream'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%repRing"></input><input type="%mult%l"></input></inputs><script><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block s="reportListItem"><l>1</l><block var="stream"/></block><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><custom-block s="%s in front of stream %anyUE"><block s="evaluate"><block var="function"/><custom-block s="map %repRing over %mult%l"><block s="reifyReporter"><autolambda><custom-block s="head of stream %l"><l/></custom-block></autolambda><list></list></block><list><block var="stream"/></list></custom-block></block><custom-block s="map %repRing over stream %mult%l"><block var="function"/><custom-block s="map %repRing over %mult%l"><block s="reifyReporter"><autolambda><custom-block s="tail of stream %l"><l/></custom-block></autolambda><list></list></block><list><block var="stream"/></list></custom-block></custom-block></custom-block></block></script></block></script></block-definition><block-definition s="keep items such that %'pred' from stream %'stream'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%predRing"></input><input type="%l"></input></inputs><script><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block var="stream"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doIfElse"><block s="evaluate"><block var="pred"/><list><custom-block s="head of stream %l"><block var="stream"/></custom-block></list></block><script><block s="doReport"><custom-block s="%s in front of stream %anyUE"><custom-block s="head of stream %l"><block var="stream"/></custom-block><custom-block s="keep items such that %predRing from stream %l"><block var="pred"/><custom-block s="tail of stream %l"><block var="stream"/></custom-block></custom-block></custom-block></block></script><script><block s="doReport"><custom-block s="keep items such that %predRing from stream %l"><block var="pred"/><custom-block s="tail of stream %l"><block var="stream"/></custom-block></custom-block></block></script></block></script></block></script></block-definition><block-definition s="map %'function' over %'lists'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%repRing"></input><input type="%mult%l"></input></inputs><script><block s="doWarp"><script><block s="doDeclareVariables"><list><l>mapone</l><l>mapmany</l></list></block><block s="doSetVar"><l>mapone</l><block s="reifyScript"><script><block s="doIf"><custom-block s="empty? %l"><block var="data"/></custom-block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><block s="reportCONS"><block s="evaluate"><block var="function"/><list><block s="reportListItem"><l>1</l><block var="data"/></block></list></block><block s="evaluate"><block var="mapone"/><list><block s="reportCDR"><block var="data"/></block></list></block></block></block></script><list><l>data</l></list></block></block><block s="doSetVar"><l>mapmany</l><block s="reifyScript"><script><block s="doIf"><custom-block s="empty? %l"><block s="reportListItem"><l>1</l><block var="data lists"/></block></custom-block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><block s="reportCONS"><block s="evaluate"><block var="function"/><custom-block s="map %repRing over %mult%l"><block s="reifyReporter"><autolambda><block s="reportListItem"><l>1</l><l/></block></autolambda><list></list></block><list><block var="data lists"/></list></custom-block></block><block s="evaluate"><block var="mapmany"/><list><custom-block s="map %repRing over %mult%l"><block s="reifyReporter"><autolambda><block s="reportCDR"><l/></block></autolambda><list></list></block><list><block var="data lists"/></list></custom-block></list></block></block></block></script><list><l>data lists</l></list></block></block><block s="doIfElse"><custom-block s="empty? %l"><block s="reportCDR"><block var="lists"/></block></custom-block><script><block s="doReport"><block s="evaluate"><block var="mapone"/><list><block s="reportListItem"><l>1</l><block var="lists"/></block></list></block></block></script><script><block s="doReport"><block s="evaluate"><block var="mapmany"/><list><block var="lists"/></list></block></block></script></block></script></block></script></block-definition><block-definition s="empty? %'data'" type="predicate" category="lists"><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doReport"><block s="reportEquals"><block var="data"/><block s="reportNewList"><list></list></block></block></block></script></block-definition><block-definition s="show stream %'stream' %'number'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%l"></input><input type="%n">10</input></inputs><script><block s="doIf"><custom-block s="empty? %l"><block var="stream"/></custom-block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doIf"><block s="reportEquals"><block var="number"/><l>0</l></block><script><block s="doReport"><block s="reportNewList"><list></list></block></block></script></block><block s="doReport"><block s="reportCONS"><custom-block s="head of stream %l"><block var="stream"/></custom-block><custom-block s="show stream %l %n"><custom-block s="tail of stream %l"><block var="stream"/></custom-block><block s="reportDifference"><block var="number"/><l>1</l></block></custom-block></block></block></script></block-definition><block-definition s="sieve %'stream'" type="reporter" category="lists"><header></header><code></code><inputs><input type="%l"></input></inputs><script><block s="doWarp"><script><block s="doReport"><custom-block s="%s in front of stream %anyUE"><custom-block s="head of stream %l"><block var="stream"/></custom-block><custom-block s="sieve %l"><custom-block s="keep items such that %predRing from stream %l"><block s="reifyPredicate"><autolambda><block s="reportGreaterThan"><block s="reportModulus"><l></l><custom-block s="head of stream %l"><block var="stream"/></custom-block></block><l>0</l></block></autolambda><list></list></block><custom-block s="tail of stream %l"><block var="stream"/></custom-block></custom-block></custom-block></custom-block></block></script></block></script></block-definition></blocks>
\ No newline at end of file diff --git a/libraries/variadic-reporters.xml b/libraries/variadic-reporters.xml new file mode 100644 index 0000000..d6ae177 --- /dev/null +++ b/libraries/variadic-reporters.xml @@ -0,0 +1 @@ +<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="sum %'nums'" type="reporter" category="operators"><comment x="0" y="0" w="202" collapsed="false">Takes any number of numbers as inputs (use the left and right arrowheads to adjust the number of input slots) and reports the result of adding them all, so
ISUM (4) (100) (8))
reports 112.</comment><code></code><inputs><input type="%mult%n"></input></inputs><script><block s="doIf"><block s="reportEquals"><block var="nums"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><l>0</l></block></script></block><block s="doReport"><block s="reportSum"><block s="reportListItem"><l>1</l><block var="nums"/></block><custom-block s="sum %mult%n"><block s="reportCDR"><block var="nums"/></block></custom-block></block></block></script></block-definition><block-definition s="product %'nums'" type="reporter" category="operators"><comment x="0" y="0" w="205" collapsed="false">Takes any number of numbers as inputs (use the left and right arrowheads to adjust the number of input slots) and reports the result of multiplying them all, so
(PRODUCT (4) (100) (8))
reports 3200.</comment><code></code><inputs><input type="%mult%n"></input></inputs><script><block s="doIf"><block s="reportEquals"><block var="nums"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><l>1</l></block></script></block><block s="doReport"><block s="reportProduct"><block s="reportListItem"><l>1</l><block var="nums"/></block><custom-block s="product %mult%n"><block s="reportCDR"><block var="nums"/></block></custom-block></block></block></script></block-definition><block-definition s="all of %'preds'" type="predicate" category="operators"><comment x="0" y="0" w="248" collapsed="false">Takes any number of Boolean (true/false) inputs (use the left and right arrowheads to adjust the number of input slots) and reports TRUE only if all of the inputs are TRUE, otherwise FALSE. Like AND but for multiple inputs.</comment><code></code><inputs><input type="%mult%boolUE"></input></inputs><script><block s="doIf"><block s="reportEquals"><block var="preds"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportTrue"></block></block></script></block><block s="doReport"><block s="reportAnd"><block s="evaluate"><block s="reportListItem"><l>1</l><block var="preds"/></block><list></list></block><custom-block s="all of %mult%boolUE"><block s="reportCDR"><block var="preds"/></block></custom-block></block></block></script></block-definition><block-definition s="any of %'preds'" type="predicate" category="operators"><comment x="0" y="0" w="240" collapsed="false">Takes any number of Boolean (true/false) inputs (use the left and right arrowheads to adjust the number of input slots) and reports TRUE if at least one input is TRUE, otherwise FALSE.</comment><code></code><inputs><input type="%mult%boolUE"></input></inputs><script><block s="doIf"><block s="reportEquals"><block var="preds"/><block s="reportNewList"><list></list></block></block><script><block s="doReport"><block s="reportFalse"></block></block></script></block><block s="doReport"><block s="reportOr"><block s="evaluate"><block s="reportListItem"><l>1</l><block var="preds"/></block><list></list></block><custom-block s="any of %mult%boolUE"><block s="reportCDR"><block var="preds"/></block></custom-block></block></block></script></block-definition></blocks>
\ No newline at end of file diff --git a/libraries/word-sentence.xml b/libraries/word-sentence.xml new file mode 100644 index 0000000..ff2a1a7 --- /dev/null +++ b/libraries/word-sentence.xml @@ -0,0 +1 @@ +<blocks app="Snap! 4.0, http://snap.berkeley.edu" version="1"><block-definition s="all but first letter of %'string'" type="reporter" category="operators"><comment x="0" y="0" w="199" collapsed="false">Takes a text string as input, and reports a new text string containing all but the first character of the input.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>result</l><l>i</l></list></block><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="string"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportSum"><l>0</l><l>0</l></block></block></block></script></block><block s="doSetVar"><l>result</l><l></l></block><block s="doSetVar"><l>i</l><l>2</l></block><block s="doUntil"><block s="reportGreaterThan"><block var="i"/><block s="reportStringSize"><block var="string"/></block></block><script><block s="doSetVar"><l>result</l><block s="reportJoinWords"><list><block var="result"/><block s="reportLetter"><block var="i"/><block var="string"/></block></list></block></block><block s="doChangeVar"><l>i</l><l>1</l></block></script></block><block s="doReport"><block var="result"/></block></script></block></script></block-definition><block-definition s="all but first word of %'sentence'" type="reporter" category="operators"><comment x="0" y="0" w="223.000001" collapsed="false">Takes a text string as input, divides it into words treating one or more spaces as a word separator (only spaces count; punctuation is part of the word) and reports a text string containing all but the first word, with one space between words and no spaces at the beginning or end. (Note: consider using SENTENCE->LIST and processing the resulting list instead of doing recursion on sentences in text string form. List operations are faster.)</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>index</l><l>bf</l></list></block><block s="doWarp"><script><block s="doSetVar"><l>bf</l><l></l></block><block s="doSetVar"><l>index</l><l>1</l></block><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="sentence"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doIf"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><script><block s="doReport"><l></l></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><l></l></block></script></block><block s="doUntil"><block s="reportGreaterThan"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><script><block s="doSetVar"><l>bf</l><block s="reportJoinWords"><list><block var="bf"/><block s="reportLetter"><block var="index"/><block var="sentence"/></block></list></block></block><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doReport"><block var="bf"/></block></script></block></script></block-definition><block-definition s="all but last letter of %'string'" type="reporter" category="operators"><comment x="0" y="0" w="218" collapsed="false">Takes a text string as input, and reports a new text string containing all but the last letter of the input.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>result</l><l>i</l></list></block><block s="doWarp"><script><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="string"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportSum"><l>0</l><l>0</l></block></block></block></script></block><block s="doSetVar"><l>result</l><l></l></block><block s="doSetVar"><l>i</l><l>1</l></block><block s="doUntil"><block s="reportEquals"><block var="i"/><block s="reportStringSize"><block var="string"/></block></block><script><block s="doSetVar"><l>result</l><block s="reportJoinWords"><list><block var="result"/><block s="reportLetter"><block var="i"/><block var="string"/></block></list></block></block><block s="doChangeVar"><l>i</l><l>1</l></block></script></block><block s="doReport"><block var="result"/></block></script></block></script></block-definition><block-definition s="all but last word of %'sentence'" type="reporter" category="operators"><comment x="0" y="0" w="212" collapsed="false">Takes a text string as input, divides it into words treating one or more spaces as a word separator (only spaces count; punctuation is part of the word) and reports a text string containing all but the last word, with one space between words and no spaces at the beginning or end. (Note: consider using SENTENCE->LIST and processing the resulting list instead of doing recursion on sentences in text string form. List operations are faster.)</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>index</l><l>bl</l></list></block><block s="doWarp"><script><block s="doSetVar"><l>bl</l><l></l></block><block s="doSetVar"><l>index</l><block s="reportStringSize"><block var="sentence"/></block></block><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="sentence"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><l>1</l></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><l>1</l></block><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doIf"><block s="reportEquals"><block var="index"/><l>1</l></block><script><block s="doReport"><l></l></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><l>1</l></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><l></l></block></script></block><block s="doUntil"><block s="reportLessThan"><block var="index"/><l>1</l></block><script><block s="doSetVar"><l>bl</l><block s="reportJoinWords"><list><block s="reportLetter"><block var="index"/><block var="sentence"/></block><block var="bl"/></list></block></block><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doReport"><block var="bl"/></block></script></block></script></block-definition><block-definition s="first word of %'sentence'" type="reporter" category="operators"><comment x="0" y="0" w="236" collapsed="false">Takes a text string as input, divides it into words treating one or more spaces as a word separator (only spaces count; punctuation is part of the word) and reports a text string containing only the first word, with no spaces before or after it.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>index</l><l>first</l></list></block><block s="doWarp"><script><block s="doSetVar"><l>first</l><l></l></block><block s="doSetVar"><l>index</l><l>1</l></block><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="sentence"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doSetVar"><l>first</l><block s="reportJoinWords"><list><block var="first"/><block s="reportLetter"><block var="index"/><block var="sentence"/></block></list></block></block><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doIf"><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doSetVar"><l>first</l><block s="reportJoinWords"><list><block var="first"/><block s="reportLetter"><block var="index"/><block var="sentence"/></block></list></block></block></script></block><block s="doReport"><block var="first"/></block></script></block></script></block-definition><block-definition s="last letter of %'word'" type="reporter" category="operators"><comment x="0" y="0" w="260" collapsed="false">Takes a text string as input, and reports the last character in the string.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doReport"><block s="reportLetter"><block s="reportStringSize"><block var="word"/></block><block var="word"/></block></block></script></block-definition><block-definition s="last word of %'sentence'" type="reporter" category="operators"><comment x="0" y="0" w="262" collapsed="false">Takes a text string as input, divides it into words treating one or more spaces as a word separator (only spaces count; punctuation is part of the word) and reports a text string containing only the last word of the input, with no spaces before or after it.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>index</l><l>last</l></list></block><block s="doWarp"><script><block s="doSetVar"><l>last</l><l></l></block><block s="doSetVar"><l>index</l><block s="reportStringSize"><block var="sentence"/></block></block><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="sentence"/></block><l>0</l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><l>1</l></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doIf"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block><script><block s="doReport"><block s="reportListItem"><l>1</l><block s="reportJoinWords"><list><l>empty </l><l>sentence</l></list></block></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><l>1</l></block><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doSetVar"><l>last</l><block s="reportJoinWords"><list><block s="reportLetter"><block var="index"/><block var="sentence"/></block><block var="last"/></list></block></block><block s="doChangeVar"><l>index</l><l>-1</l></block></script></block><block s="doIf"><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block><script><block s="doSetVar"><l>last</l><block s="reportJoinWords"><list><block s="reportLetter"><block var="index"/><block var="sentence"/></block><block var="last"/></list></block></block></script></block><block s="doReport"><block var="last"/></block></script></block></script></block-definition><block-definition s="empty word? %'word'" type="predicate" category="operators"><comment x="0" y="0" w="208" collapsed="false">Takes a text string as input, and reports TRUE if the string has no characters in it of any kind, otherwise false.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doReport"><block s="reportEquals"><block s="reportStringSize"><block var="word"/></block><l>0</l></block></block></script></block-definition><block-definition s="empty sentence? %'sentence'" type="predicate" category="operators"><comment x="0" y="0" w="221" collapsed="false">Takes a text string as input, and reports TRUE if the input contains no characters other than spaces (therefore, no words when the string is considered as a sentence), otherwise FALSE.</comment><header></header><code></code><inputs><input type="%txt"></input></inputs><script><block s="doDeclareVariables"><list><l>index</l></list></block><block s="doSetVar"><l>index</l><l>1</l></block><block s="doIf"><block s="reportEquals"><block s="reportStringSize"><block var="sentence"/></block><l>0</l></block><script><block s="doReport"><block s="reportTrue"></block></block></script></block><block s="doUntil"><block s="reportOr"><block s="reportEquals"><block var="index"/><block s="reportStringSize"><block var="sentence"/></block></block><block s="reportNot"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></block><script><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doReport"><block s="reportEquals"><block s="reportLetter"><block var="index"/><block var="sentence"/></block><l> </l></block></block></script></block-definition><block-definition s="word->list %'text'" type="reporter" category="operators"><comment w="160" collapsed="false">Takes a text string as input, and reports a list in which each item is a single character from the string.</comment><header></header><code></code><inputs><input type="%s"></input></inputs><script><block s="doDeclareVariables"><list><l>result</l><l>index</l></list></block><block s="doSetVar"><l>result</l><block s="reportNewList"><list></list></block></block><block s="doSetVar"><l>index</l><l>1</l></block><block s="doUntil"><block s="reportGreaterThan"><block var="index"/><block s="reportStringSize"><block var="text"/></block></block><script><block s="doAddToList"><block s="reportLetter"><block var="index"/><block var="text"/></block><block var="result"/></block><block s="doChangeVar"><l>index</l><l>1</l></block></script></block><block s="doReport"><block var="result"/></block></script></block-definition></blocks>
\ No newline at end of file @@ -7,7 +7,7 @@ written by Jens Mönig and Brian Harvey jens@moenig.org, bh@cs.berkeley.edu - Copyright (C) 2013 by Jens Mönig and Brian Harvey + Copyright (C) 2014 by Jens Mönig and Brian Harvey This file is part of Snap!. @@ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph, StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph, MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/ -modules.lists = '2013-December-04'; +modules.lists = '2014-January-09'; var List; var ListWatcherMorph; @@ -6,7 +6,7 @@ written by Jens Mönig - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -42,7 +42,7 @@ /*global modules, contains*/ -modules.locale = '2013-December-04'; +modules.locale = '2014-February-04'; // Global stuff @@ -149,7 +149,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', 'last_changed': - '2013-10-04' + '2014-02-04' }; SnapTranslator.dict.it = { @@ -209,7 +209,7 @@ SnapTranslator.dict.pt = { 'translator_e-mail': 'mmsequeira@gmail.com', 'last_changed': - '2013-11-22' + '2014-01-12' }; SnapTranslator.dict.cs = { @@ -257,7 +257,7 @@ SnapTranslator.dict.fr = { 'translator_e-mail': 'i.scool@mac.com', 'last_changed': - '2013-12-04' + '2014-02-04' }; SnapTranslator.dict.si = { @@ -8,7 +8,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -1035,7 +1035,7 @@ /*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio, FileList, getBlurredShadowSupport*/ -var morphicVersion = '2013-December-12'; +var morphicVersion = '2014-February-03'; var modules = {}; // keep track of additional loaded modules var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug @@ -3068,7 +3068,7 @@ Morph.prototype.updateReferences = function (dict) { */ var property; for (property in this) { - if (property.isMorph && dict[property]) { + if (this[property] && this[property].isMorph && dict[property]) { this[property] = dict[property]; } } @@ -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); @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -124,7 +124,7 @@ PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.objects = '2013-December-28'; +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; @@ -581,6 +582,9 @@ SpriteMorph.prototype.initBlocks = function () { category: 'control', spec: 'if %b %c else %c' }, + + /* migrated to a newer block version: + doStop: { type: 'command', category: 'control', @@ -591,6 +595,18 @@ SpriteMorph.prototype.initBlocks = function () { category: 'control', spec: 'stop all %stop' }, + */ + + doStopThis: { + type: 'command', + category: 'control', + spec: 'stop %stopChoices' + }, + doStopOthers: { + type: 'command', + category: 'control', + spec: 'stop %stopOthersChoices' + }, doRun: { type: 'command', category: 'control', @@ -630,11 +646,13 @@ SpriteMorph.prototype.initBlocks = function () { category: 'control', spec: 'report %s' }, - doStopBlock: { + /* + doStopBlock: { // migrated to a newer block version type: 'command', category: 'control', spec: 'stop block' }, + */ doCallCC: { type: 'command', category: 'control', @@ -1084,6 +1102,25 @@ SpriteMorph.prototype.initBlocks = function () { SpriteMorph.prototype.initBlocks(); +SpriteMorph.prototype.initBlockMigrations = function () { + SpriteMorph.prototype.blockMigrations = { + doStopAll: { + selector: 'doStopThis', + inputs: [['all']] + }, + doStop: { + selector: 'doStopThis', + inputs: [['this script']] + }, + doStopBlock: { + selector: 'doStopThis', + inputs: [['this block']] + } + }; +}; + +SpriteMorph.prototype.initBlockMigrations(); + SpriteMorph.prototype.blockAlternatives = { // motion: turn: ['turnLeft'], @@ -1130,9 +1167,6 @@ SpriteMorph.prototype.blockAlternatives = { receiveClick: ['receiveGo'], doBroadcast: ['doBroadcastAndWait'], doBroadcastAndWait: ['doBroadcast'], - doStopBlock: ['doStop', 'doStopAll'], - doStop: ['doStopBlock', 'doStopAll'], - doStopAll: ['doStopBlock', 'doStop'], // sensing: getLastAnswer: ['getTimer'], @@ -1412,8 +1446,9 @@ SpriteMorph.prototype.colorFiltered = function (aColor) { // SpriteMorph block instantiation SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) { - var info, block, defaults, inputs, i; - info = this.blocks[selector]; + var migration, info, block, defaults, inputs, i; + migration = this.blockMigrations[selector]; + info = this.blocks[migration ? migration.selector : selector]; if (!info) {return null; } block = info.type === 'command' ? new CommandBlockMorph() : info.type === 'hat' ? new HatBlockMorph() @@ -1426,8 +1461,8 @@ SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) { block.isStatic = true; } block.setSpec(localize(info.spec)); - if (setDefaults && info.defaults) { - defaults = info.defaults; + if ((setDefaults && info.defaults) || (migration && migration.inputs)) { + defaults = migration ? migration.inputs : info.defaults; block.defaults = defaults; inputs = block.inputs(); if (inputs[0] instanceof MultiArgMorph) { @@ -1651,9 +1686,14 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push('-'); blocks.push(block('doReport')); blocks.push('-'); + /* + // old STOP variants, migrated to a newer version, now redundant blocks.push(block('doStopBlock')); blocks.push(block('doStop')); blocks.push(block('doStopAll')); + */ + blocks.push(block('doStopThis')); + blocks.push(block('doStopOthers')); blocks.push('-'); blocks.push(block('doRun')); blocks.push(block('fork')); @@ -2685,8 +2725,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); @@ -4359,9 +4404,14 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push('-'); blocks.push(block('doReport')); blocks.push('-'); + /* + // old STOP variants, migrated to a newer version, now redundant blocks.push(block('doStopBlock')); blocks.push(block('doStop')); blocks.push(block('doStopAll')); + */ + blocks.push(block('doStopThis')); + blocks.push(block('doStopOthers')); blocks.push('-'); blocks.push(block('doRun')); blocks.push(block('fork')); @@ -5272,7 +5322,10 @@ Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) { function (img, rc) { myself.contents = img; myself.rotationCenter = rc; - myself.shrinkWrap(); + if (anIDE.currentSprite instanceof SpriteMorph) { + // don't shrinkwrap stage costumes + myself.shrinkWrap(); + } myself.version = Date.now(); aWorld.changed(); if (anIDE) { @@ -5609,17 +5662,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 }; @@ -5627,17 +5684,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; } }; @@ -1,14 +1,14 @@ -/*
+/* paint.js -
- a paint editor for Snap!
- inspired by the Scratch paint editor.
-
+ + a paint editor for Snap! + inspired by the Scratch paint editor. + written by Kartik Chandra - Copyright (C) 2013 by Kartik Chandra
-
- This file is part of Snap!.
-
+ Copyright (C) 2014 by Kartik Chandra + + This file is part of Snap!. + Snap! is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of @@ -50,186 +50,187 @@ May 16 - flat design adjustments (Jens) July 12 - pipette tool, code formatting adjustments (Jens) September 16 - flood fill freeze fix (Kartik) + Jan 08 - mouse leave dragging fix (Kartik) + + */ - */
-
-/*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph,
- FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph,
- CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph,
- TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph,
+/*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph, + FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph, + CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph, + TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph, ToggleMorph, ToggleButtonMorph, BoxMorph, modules, radians, - MorphicPreferences, getDocumentPositionOf
- */
-
+ MorphicPreferences, getDocumentPositionOf + */ + // Global stuff //////////////////////////////////////////////////////// -modules.paint = '2013-September-16'; +modules.paint = '2014-January-09'; // Declarations -var PaintEditorMorph;
-var PaintCanvasMorph;
-var PaintColorPickerMorph;
-
-// PaintEditorMorph //////////////////////////
+var PaintEditorMorph; +var PaintCanvasMorph; +var PaintColorPickerMorph; + +// PaintEditorMorph ////////////////////////// + +// A complete paint editor -// A complete paint editor
-
-PaintEditorMorph.prototype = new DialogBoxMorph();
-PaintEditorMorph.prototype.constructor = PaintEditorMorph;
-PaintEditorMorph.uber = DialogBoxMorph.prototype;
-
-PaintEditorMorph.prototype.padding = 10;
-
-function PaintEditorMorph() {
- this.init();
-}
-
-PaintEditorMorph.prototype.init = function () {
- // additional properties:
+PaintEditorMorph.prototype = new DialogBoxMorph(); +PaintEditorMorph.prototype.constructor = PaintEditorMorph; +PaintEditorMorph.uber = DialogBoxMorph.prototype; + +PaintEditorMorph.prototype.padding = 10; + +function PaintEditorMorph() { + this.init(); +} + +PaintEditorMorph.prototype.init = function () { + // additional properties: this.paper = null; // paint canvas - this.oncancel = null;
-
- // initialize inherited properties:
- PaintEditorMorph.uber.init.call(this);
-
- // override inherited properties:
- this.labelString = "Paint Editor";
- this.createLabel();
-
- // build contents:
- this.buildContents();
-};
-
-PaintEditorMorph.prototype.buildContents = function () {
- var myself = this;
-
+ this.oncancel = null; + + // initialize inherited properties: + PaintEditorMorph.uber.init.call(this); + + // override inherited properties: + this.labelString = "Paint Editor"; + this.createLabel(); + + // build contents: + this.buildContents(); +}; + +PaintEditorMorph.prototype.buildContents = function () { + var myself = this; + this.paper = new PaintCanvasMorph(function () {return myself.shift; }); - this.paper.setExtent(new Point(480, 360));
-
- this.addBody(new AlignmentMorph('row', this.padding));
- this.controls = new AlignmentMorph('column', this.padding);
- this.controls.alignment = 'left';
-
- this.edits = new AlignmentMorph('row', this.padding);
- this.buildEdits();
- this.controls.add(this.edits);
-
- this.body.color = this.color;
-
- this.body.add(this.controls);
- this.body.add(this.paper);
-
- this.toolbox = new BoxMorph();
- this.toolbox.color = SpriteMorph.prototype.paletteColor.lighter(8);
+ this.paper.setExtent(new Point(480, 360)); + + this.addBody(new AlignmentMorph('row', this.padding)); + this.controls = new AlignmentMorph('column', this.padding); + this.controls.alignment = 'left'; + + this.edits = new AlignmentMorph('row', this.padding); + this.buildEdits(); + this.controls.add(this.edits); + + this.body.color = this.color; + + this.body.add(this.controls); + this.body.add(this.paper); + + this.toolbox = new BoxMorph(); + this.toolbox.color = SpriteMorph.prototype.paletteColor.lighter(8); this.toolbox.borderColor = this.toolbox.color.lighter(40); if (MorphicPreferences.isFlat) { this.toolbox.edge = 0; - }
-
- this.buildToolbox();
- this.controls.add(this.toolbox);
-
- this.propertiesControls = {
- colorpicker: null,
- penSizeSlider: null,
- penSizeField: null,
- primaryColorButton: null,
- primaryColorViewer: null,
- constrain: null
- };
- this.populatePropertiesMenu();
-
- this.addButton("ok", "OK");
- this.addButton("cancel", "Cancel");
-
- this.refreshToolButtons();
- this.fixLayout();
- this.drawNew();
-};
-
-PaintEditorMorph.prototype.buildToolbox = function () {
- var tools = {
- brush:
- "Paintbrush tool\n(free draw)",
- rectangle:
- "Stroked Rectangle\n(shift: square)",
- circle:
- "Stroked Ellipse\n(shift: circle)",
- eraser:
- "Eraser tool",
- crosshairs:
- "Set the rotation center",
-
- line:
- "Line tool\n(shift: vertical/horizontal)",
- rectangleSolid:
- "Filled Rectangle\n(shift: square)",
- circleSolid:
- "Filled Ellipse\n(shift: circle)",
- paintbucket:
- "Fill a region",
+ } + + this.buildToolbox(); + this.controls.add(this.toolbox); + + this.propertiesControls = { + colorpicker: null, + penSizeSlider: null, + penSizeField: null, + primaryColorButton: null, + primaryColorViewer: null, + constrain: null + }; + this.populatePropertiesMenu(); + + this.addButton("ok", "OK"); + this.addButton("cancel", "Cancel"); + + this.refreshToolButtons(); + this.fixLayout(); + this.drawNew(); +}; + +PaintEditorMorph.prototype.buildToolbox = function () { + var tools = { + brush: + "Paintbrush tool\n(free draw)", + rectangle: + "Stroked Rectangle\n(shift: square)", + circle: + "Stroked Ellipse\n(shift: circle)", + eraser: + "Eraser tool", + crosshairs: + "Set the rotation center", + + line: + "Line tool\n(shift: vertical/horizontal)", + rectangleSolid: + "Filled Rectangle\n(shift: square)", + circleSolid: + "Filled Ellipse\n(shift: circle)", + paintbucket: + "Fill a region", pipette: "Pipette tool\n(pick a color anywhere)" - },
- myself = this,
- left = this.toolbox.left(),
- top = this.toolbox.top(),
- padding = 2,
- inset = 5,
- x = 0,
- y = 0;
-
- Object.keys(tools).forEach(function (tool) {
- var btn = myself.toolButton(tool, tools[tool]);
- btn.setPosition(new Point(
- left + x,
- top + y
- ));
- x += btn.width() + padding;
- if (tool === "crosshairs") {
- x = 0;
- y += btn.height() + padding;
- myself.paper.drawcrosshair();
- }
- myself.toolbox[tool] = btn;
- myself.toolbox.add(btn);
- });
-
- this.toolbox.bounds = this.toolbox.fullBounds().expandBy(inset * 2);
- this.toolbox.drawNew();
-};
-
-PaintEditorMorph.prototype.buildEdits = function () {
- var paper = this.paper;
-
- this.edits.add(this.pushButton(
- "undo",
- function () {paper.undo(); }
- ));
-
- this.edits.add(this.pushButton(
- "clear",
- function () {paper.clearCanvas(); }
- ));
- this.edits.fixLayout();
-};
-
-PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) {
+ }, + myself = this, + left = this.toolbox.left(), + top = this.toolbox.top(), + padding = 2, + inset = 5, + x = 0, + y = 0; + + Object.keys(tools).forEach(function (tool) { + var btn = myself.toolButton(tool, tools[tool]); + btn.setPosition(new Point( + left + x, + top + y + )); + x += btn.width() + padding; + if (tool === "crosshairs") { + x = 0; + y += btn.height() + padding; + myself.paper.drawcrosshair(); + } + myself.toolbox[tool] = btn; + myself.toolbox.add(btn); + }); + + this.toolbox.bounds = this.toolbox.fullBounds().expandBy(inset * 2); + this.toolbox.drawNew(); +}; + +PaintEditorMorph.prototype.buildEdits = function () { + var paper = this.paper; + + this.edits.add(this.pushButton( + "undo", + function () {paper.undo(); } + )); + + this.edits.add(this.pushButton( + "clear", + function () {paper.clearCanvas(); } + )); + this.edits.fixLayout(); +}; + +PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) { // Open the editor in a world with an optional image to edit - this.oldim = oldim;
- this.oldrc = oldrc.copy();
- this.callback = callback || nop;
+ this.oldim = oldim; + this.oldrc = oldrc.copy(); + this.callback = callback || nop; - this.processKeyUp = function () {
- this.shift = false;
- this.propertiesControls.constrain.refresh();
- };
+ this.processKeyUp = function () { + this.shift = false; + this.propertiesControls.constrain.refresh(); + }; - this.processKeyDown = function () {
- this.shift = this.world().currentKey === 16;
- this.propertiesControls.constrain.refresh();
- };
+ this.processKeyDown = function () { + this.shift = this.world().currentKey === 16; + this.propertiesControls.constrain.refresh(); + }; //merge oldim: if (this.oldim) { @@ -244,170 +245,170 @@ PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) { this.paper.drawNew(); } - this.key = 'paint';
- this.popUp(world);
-};
-
+ this.key = 'paint'; + this.popUp(world); +}; + PaintEditorMorph.prototype.fixLayout = function () { var oldFlag = Morph.prototype.trackChanges; -
+ this.changed(); oldFlag = Morph.prototype.trackChanges; Morph.prototype.trackChanges = false; if (this.paper) { this.paper.buildContents(); - this.paper.drawNew();
- }
- if (this.controls) {this.controls.fixLayout(); }
- if (this.body) {this.body.fixLayout(); }
- PaintEditorMorph.uber.fixLayout.call(this);
+ this.paper.drawNew(); + } + if (this.controls) {this.controls.fixLayout(); } + if (this.body) {this.body.fixLayout(); } + PaintEditorMorph.uber.fixLayout.call(this); Morph.prototype.trackChanges = oldFlag; this.changed(); -};
-
-PaintEditorMorph.prototype.refreshToolButtons = function () {
- this.toolbox.children.forEach(function (toggle) {
- toggle.refresh();
- });
-};
-
-PaintEditorMorph.prototype.ok = function () {
- this.callback(
- this.paper.paper,
- this.paper.rotationCenter
- );
- this.destroy();
-};
+}; + +PaintEditorMorph.prototype.refreshToolButtons = function () { + this.toolbox.children.forEach(function (toggle) { + toggle.refresh(); + }); +}; + +PaintEditorMorph.prototype.ok = function () { + this.callback( + this.paper.paper, + this.paper.rotationCenter + ); + this.destroy(); +}; PaintEditorMorph.prototype.cancel = function () { if (this.oncancel) {this.oncancel(); } this.destroy(); }; -
-PaintEditorMorph.prototype.populatePropertiesMenu = function () {
- var c = this.controls,
- myself = this,
- pc = this.propertiesControls,
- alpen = new AlignmentMorph("row", this.padding);
-
- pc.primaryColorViewer = new Morph();
- pc.primaryColorViewer.setExtent(new Point(180, 50));
- pc.primaryColorViewer.color = new Color(0, 0, 0);
- pc.colorpicker = new PaintColorPickerMorph(
- new Point(180, 100),
- function (color) {
- var ni = newCanvas(pc.primaryColorViewer.extent()),
- ctx = ni.getContext("2d"),
- i,
- j;
- myself.paper.settings.primarycolor = color;
- if (color === "transparent") {
- for (i = 0; i < 180; i += 5) {
- for (j = 0; j < 15; j += 5) {
- ctx.fillStyle =
- ((j + i) / 5) % 2 === 0 ?
- "rgba(0, 0, 0, 0.2)" :
- "rgba(0, 0, 0, 0.5)";
- ctx.fillRect(i, j, 5, 5);
-
- }
- }
- } else {
- ctx.fillStyle = color.toString();
- ctx.fillRect(0, 0, 180, 15);
- }
- ctx.strokeStyle = "black";
- ctx.lineWidth = Math.min(myself.paper.settings.linewidth, 20);
- ctx.beginPath();
- ctx.lineCap = "round";
- ctx.moveTo(20, 30);
- ctx.lineTo(160, 30);
- ctx.stroke();
- pc.primaryColorViewer.image = ni;
- pc.primaryColorViewer.changed();
- }
- );
- pc.colorpicker.action(new Color(0, 0, 0));
-
- pc.penSizeSlider = new SliderMorph(0, 20, 5, 5);
- pc.penSizeSlider.orientation = "horizontal";
- pc.penSizeSlider.setHeight(15);
- pc.penSizeSlider.setWidth(150);
- pc.penSizeSlider.action = function (num) {
- if (pc.penSizeField) {
- pc.penSizeField.setContents(num);
- }
- myself.paper.settings.linewidth = num;
- pc.colorpicker.action(myself.paper.settings.primarycolor);
- };
- pc.penSizeField = new InputFieldMorph("5", true, null, false);
- pc.penSizeField.contents().minWidth = 20;
- pc.penSizeField.setWidth(25);
- pc.penSizeField.accept = function () {
- var val = parseFloat(pc.penSizeField.getValue());
- pc.penSizeSlider.value = val;
- pc.penSizeSlider.drawNew();
- pc.penSizeSlider.updateValue();
- this.setContents(val);
- myself.paper.settings.linewidth = val;
- this.world().keyboardReceiver = myself;
- pc.colorpicker.action(myself.paper.settings.primarycolor);
- };
- alpen.add(pc.penSizeSlider);
- alpen.add(pc.penSizeField);
- alpen.color = myself.color;
- alpen.fixLayout();
- pc.penSizeField.drawNew();
- pc.constrain = new ToggleMorph(
- "checkbox",
- this,
- function () {myself.shift = !myself.shift; },
- "Constrain proportions of shapes?\n(you can also hold shift)",
- function () {return myself.shift; }
- );
- c.add(pc.colorpicker);
- //c.add(pc.primaryColorButton);
- c.add(pc.primaryColorViewer);
- c.add(new TextMorph("Brush size"));
- c.add(alpen);
- c.add(pc.constrain);
-};
-
-PaintEditorMorph.prototype.toolButton = function (icon, hint) {
- var button, myself = this;
-
- button = new ToggleButtonMorph(
- null,
+ +PaintEditorMorph.prototype.populatePropertiesMenu = function () { + var c = this.controls, + myself = this, + pc = this.propertiesControls, + alpen = new AlignmentMorph("row", this.padding); + + pc.primaryColorViewer = new Morph(); + pc.primaryColorViewer.setExtent(new Point(180, 50)); + pc.primaryColorViewer.color = new Color(0, 0, 0); + pc.colorpicker = new PaintColorPickerMorph( + new Point(180, 100), + function (color) { + var ni = newCanvas(pc.primaryColorViewer.extent()), + ctx = ni.getContext("2d"), + i, + j; + myself.paper.settings.primarycolor = color; + if (color === "transparent") { + for (i = 0; i < 180; i += 5) { + for (j = 0; j < 15; j += 5) { + ctx.fillStyle = + ((j + i) / 5) % 2 === 0 ? + "rgba(0, 0, 0, 0.2)" : + "rgba(0, 0, 0, 0.5)"; + ctx.fillRect(i, j, 5, 5); + + } + } + } else { + ctx.fillStyle = color.toString(); + ctx.fillRect(0, 0, 180, 15); + } + ctx.strokeStyle = "black"; + ctx.lineWidth = Math.min(myself.paper.settings.linewidth, 20); + ctx.beginPath(); + ctx.lineCap = "round"; + ctx.moveTo(20, 30); + ctx.lineTo(160, 30); + ctx.stroke(); + pc.primaryColorViewer.image = ni; + pc.primaryColorViewer.changed(); + } + ); + pc.colorpicker.action(new Color(0, 0, 0)); + + pc.penSizeSlider = new SliderMorph(0, 20, 5, 5); + pc.penSizeSlider.orientation = "horizontal"; + pc.penSizeSlider.setHeight(15); + pc.penSizeSlider.setWidth(150); + pc.penSizeSlider.action = function (num) { + if (pc.penSizeField) { + pc.penSizeField.setContents(num); + } + myself.paper.settings.linewidth = num; + pc.colorpicker.action(myself.paper.settings.primarycolor); + }; + pc.penSizeField = new InputFieldMorph("5", true, null, false); + pc.penSizeField.contents().minWidth = 20; + pc.penSizeField.setWidth(25); + pc.penSizeField.accept = function () { + var val = parseFloat(pc.penSizeField.getValue()); + pc.penSizeSlider.value = val; + pc.penSizeSlider.drawNew(); + pc.penSizeSlider.updateValue(); + this.setContents(val); + myself.paper.settings.linewidth = val; + this.world().keyboardReceiver = myself; + pc.colorpicker.action(myself.paper.settings.primarycolor); + }; + alpen.add(pc.penSizeSlider); + alpen.add(pc.penSizeField); + alpen.color = myself.color; + alpen.fixLayout(); + pc.penSizeField.drawNew(); + pc.constrain = new ToggleMorph( + "checkbox", + this, + function () {myself.shift = !myself.shift; }, + "Constrain proportions of shapes?\n(you can also hold shift)", + function () {return myself.shift; } + ); + c.add(pc.colorpicker); + //c.add(pc.primaryColorButton); + c.add(pc.primaryColorViewer); + c.add(new TextMorph("Brush size")); + c.add(alpen); + c.add(pc.constrain); +}; + +PaintEditorMorph.prototype.toolButton = function (icon, hint) { + var button, myself = this; + + button = new ToggleButtonMorph( + null, this, function () { // action - myself.paper.currentTool = icon;
- myself.paper.toolChanged(icon);
+ myself.paper.currentTool = icon; + myself.paper.toolChanged(icon); myself.refreshToolButtons(); if (icon === 'pipette') { myself.getUserColor(); - }
- },
- new SymbolMorph(icon, 18),
- function () {return myself.paper.currentTool === icon; }
- );
-
- button.hint = hint;
- button.drawNew();
- button.fixLayout();
- return button;
-};
-
-PaintEditorMorph.prototype.pushButton = function (title, action, hint) {
- return new PushButtonMorph(
- this,
- action,
- title,
- null,
- hint
- );
-};
+ } + }, + new SymbolMorph(icon, 18), + function () {return myself.paper.currentTool === icon; } + ); + + button.hint = hint; + button.drawNew(); + button.fixLayout(); + return button; +}; + +PaintEditorMorph.prototype.pushButton = function (title, action, hint) { + return new PushButtonMorph( + this, + action, + title, + null, + hint + ); +}; PaintEditorMorph.prototype.getUserColor = function () { var myself = this, @@ -440,167 +441,167 @@ PaintEditorMorph.prototype.getUserColor = function () { hand.processMouseUp = mouseUpBak; }; }; -
-// AdvancedColorPickerMorph //////////////////
-// A large hsl color picker
-
-PaintColorPickerMorph.prototype = new Morph();
-PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph;
-PaintColorPickerMorph.uber = Morph.prototype;
-
-function PaintColorPickerMorph(extent, action) {
- this.init(extent, action);
-}
-
-PaintColorPickerMorph.prototype.init = function (extent, action) {
- this.setExtent(extent || new Point(200, 100));
- this.action = action || nop;
- this.drawNew();
-};
-
-PaintColorPickerMorph.prototype.drawNew = function () {
- var x = 0,
- y = 0,
- can = newCanvas(this.extent()),
- ctx = can.getContext("2d"),
- colorselection,
- r;
- for (x = 0; x < this.width(); x += 1) {
- for (y = 0; y < this.height() - 20; y += 1) {
- ctx.fillStyle = "hsl(" +
- (360 * x / this.width()) +
- "," +
- "100%," +
- (y * 100 / (this.height() - 20)) +
- "%)";
- ctx.fillRect(x, y, 1, 1);
- }
- }
- for (x = 0; x < this.width(); x += 1) {
- r = Math.floor(255 * x / this.width());
- ctx.fillStyle = "rgb(" + r + ", " + r + ", " + r + ")";
- ctx.fillRect(x, this.height() - 20, 1, 10);
- }
- colorselection = ["black", "white", "gray"];
- for (x = 0; x < colorselection.length; x += 1) {
- ctx.fillStyle = colorselection[x];
- ctx.fillRect(
- x * this.width() / colorselection.length,
- this.height() - 10,
- this.width() / colorselection.length,
- 10
- );
- }
- for (x = this.width() * 2 / 3; x < this.width(); x += 2) {
- for (y = this.height() - 10; y < this.height(); y += 2) {
- if ((x + y) / 2 % 2 === 0) {
- ctx.fillStyle = "#DDD";
- ctx.fillRect(x, y, 2, 2);
- }
- }
- }
- this.image = can;
-};
-
-PaintColorPickerMorph.prototype.mouseDownLeft = function (pos) {
- if ((pos.subtract(this.position()).x > this.width() * 2 / 3) &&
- (pos.subtract(this.position()).y > this.height() - 10)) {
- this.action("transparent");
- } else {
- this.action(this.getPixelColor(pos));
- }
-};
-
-PaintColorPickerMorph.prototype.mouseMove =
+// AdvancedColorPickerMorph ////////////////// + +// A large hsl color picker + +PaintColorPickerMorph.prototype = new Morph(); +PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph; +PaintColorPickerMorph.uber = Morph.prototype; + +function PaintColorPickerMorph(extent, action) { + this.init(extent, action); +} + +PaintColorPickerMorph.prototype.init = function (extent, action) { + this.setExtent(extent || new Point(200, 100)); + this.action = action || nop; + this.drawNew(); +}; + +PaintColorPickerMorph.prototype.drawNew = function () { + var x = 0, + y = 0, + can = newCanvas(this.extent()), + ctx = can.getContext("2d"), + colorselection, + r; + for (x = 0; x < this.width(); x += 1) { + for (y = 0; y < this.height() - 20; y += 1) { + ctx.fillStyle = "hsl(" + + (360 * x / this.width()) + + "," + + "100%," + + (y * 100 / (this.height() - 20)) + + "%)"; + ctx.fillRect(x, y, 1, 1); + } + } + for (x = 0; x < this.width(); x += 1) { + r = Math.floor(255 * x / this.width()); + ctx.fillStyle = "rgb(" + r + ", " + r + ", " + r + ")"; + ctx.fillRect(x, this.height() - 20, 1, 10); + } + colorselection = ["black", "white", "gray"]; + for (x = 0; x < colorselection.length; x += 1) { + ctx.fillStyle = colorselection[x]; + ctx.fillRect( + x * this.width() / colorselection.length, + this.height() - 10, + this.width() / colorselection.length, + 10 + ); + } + for (x = this.width() * 2 / 3; x < this.width(); x += 2) { + for (y = this.height() - 10; y < this.height(); y += 2) { + if ((x + y) / 2 % 2 === 0) { + ctx.fillStyle = "#DDD"; + ctx.fillRect(x, y, 2, 2); + } + } + } + this.image = can; +}; + +PaintColorPickerMorph.prototype.mouseDownLeft = function (pos) { + if ((pos.subtract(this.position()).x > this.width() * 2 / 3) && + (pos.subtract(this.position()).y > this.height() - 10)) { + this.action("transparent"); + } else { + this.action(this.getPixelColor(pos)); + } +}; + +PaintColorPickerMorph.prototype.mouseMove = PaintColorPickerMorph.prototype.mouseDownLeft; -
+ // PaintCanvasMorph /////////////////////////// /* - A canvas which reacts to drag events to
+ A canvas which reacts to drag events to modify its image, based on a 'tool' property. */ -
-PaintCanvasMorph.prototype = new Morph();
-PaintCanvasMorph.prototype.constructor = PaintCanvasMorph;
-PaintCanvasMorph.uber = Morph.prototype;
-
-function PaintCanvasMorph(shift) {
- this.init(shift);
-}
-
-PaintCanvasMorph.prototype.init = function (shift) {
- this.rotationCenter = new Point(240, 180);
- this.dragRect = null;
- this.previousDragPoint = null;
- this.currentTool = "brush";
- this.dragRect = new Rectangle();
- // rectangle with origin being the starting drag position and
+ +PaintCanvasMorph.prototype = new Morph(); +PaintCanvasMorph.prototype.constructor = PaintCanvasMorph; +PaintCanvasMorph.uber = Morph.prototype; + +function PaintCanvasMorph(shift) { + this.init(shift); +} + +PaintCanvasMorph.prototype.init = function (shift) { + this.rotationCenter = new Point(240, 180); + this.dragRect = null; + this.previousDragPoint = null; + this.currentTool = "brush"; + this.dragRect = new Rectangle(); + // rectangle with origin being the starting drag position and // corner being the current drag position - this.mask = newCanvas(this.extent()); // Temporary canvas
- this.paper = newCanvas(this.extent()); // Actual canvas
- this.erasermask = newCanvas(this.extent()); // eraser memory
- this.background = newCanvas(this.extent()); // checkers
- this.settings = {
- "primarycolor": new Color(0, 0, 0, 255), // usually fill color
- "secondarycolor": new Color(0, 0, 0, 255), // (unused)
- "linewidth": 3 // stroke width
- };
- this.brushBuffer = [];
- this.undoBuffer = [];
- this.isShiftPressed = shift || function () {
- var key = this.world().currentKey;
- return (key === 16);
+ this.mask = newCanvas(this.extent()); // Temporary canvas + this.paper = newCanvas(this.extent()); // Actual canvas + this.erasermask = newCanvas(this.extent()); // eraser memory + this.background = newCanvas(this.extent()); // checkers + this.settings = { + "primarycolor": new Color(0, 0, 0, 255), // usually fill color + "secondarycolor": new Color(0, 0, 0, 255), // (unused) + "linewidth": 3 // stroke width + }; + this.brushBuffer = []; + this.undoBuffer = []; + this.isShiftPressed = shift || function () { + var key = this.world().currentKey; + return (key === 16); }; - this.buildContents();
-};
-
-PaintCanvasMorph.prototype.cacheUndo = function () {
- var cachecan = newCanvas(this.extent());
- this.merge(this.paper, cachecan);
- this.undoBuffer.push(cachecan);
-};
-
-PaintCanvasMorph.prototype.undo = function () {
- if (this.undoBuffer.length > 0) {
- this.paper = newCanvas(this.extent());
- this.mask.width = this.mask.width + 1 - 1;
- this.merge(this.undoBuffer.pop(), this.paper);
- this.drawNew();
- this.changed();
- }
-};
-
-PaintCanvasMorph.prototype.merge = function (a, b) {
- b.getContext("2d").drawImage(a, 0, 0);
+ this.buildContents(); }; -
-PaintCanvasMorph.prototype.centermerge = function (a, b) {
- b.getContext("2d").drawImage(
- a,
- (b.width - a.width) / 2,
- (b.height - a.height) / 2
- );
-};
-
+ +PaintCanvasMorph.prototype.cacheUndo = function () { + var cachecan = newCanvas(this.extent()); + this.merge(this.paper, cachecan); + this.undoBuffer.push(cachecan); +}; + +PaintCanvasMorph.prototype.undo = function () { + if (this.undoBuffer.length > 0) { + this.paper = newCanvas(this.extent()); + this.mask.width = this.mask.width + 1 - 1; + this.merge(this.undoBuffer.pop(), this.paper); + this.drawNew(); + this.changed(); + } +}; + +PaintCanvasMorph.prototype.merge = function (a, b) { + b.getContext("2d").drawImage(a, 0, 0); +}; + +PaintCanvasMorph.prototype.centermerge = function (a, b) { + b.getContext("2d").drawImage( + a, + (b.width - a.width) / 2, + (b.height - a.height) / 2 + ); +}; + PaintCanvasMorph.prototype.clearCanvas = function () { - this.buildContents();
- this.drawNew();
- this.changed();
-};
-
-PaintCanvasMorph.prototype.toolChanged = function (tool) {
- this.mask = newCanvas(this.extent());
- if (tool === "crosshairs") {
- this.drawcrosshair();
- }
- this.drawNew();
- this.changed();
-};
-
-PaintCanvasMorph.prototype.drawcrosshair = function (context) {
- var ctx = context || this.mask.getContext("2d"),
- rp = this.rotationCenter;
+ this.buildContents(); + this.drawNew(); + this.changed(); +}; + +PaintCanvasMorph.prototype.toolChanged = function (tool) { + this.mask = newCanvas(this.extent()); + if (tool === "crosshairs") { + this.drawcrosshair(); + } + this.drawNew(); + this.changed(); +}; + +PaintCanvasMorph.prototype.drawcrosshair = function (context) { + var ctx = context || this.mask.getContext("2d"), + rp = this.rotationCenter; ctx.lineWidth = 1; ctx.strokeStyle = 'black'; @@ -646,32 +647,32 @@ PaintCanvasMorph.prototype.drawcrosshair = function (context) { ctx.moveTo(rp.x, 0); ctx.lineTo(rp.x, this.mask.height); ctx.stroke(); -
- this.drawNew();
- this.changed();
-};
-
+ + this.drawNew(); + this.changed(); +}; + PaintCanvasMorph.prototype.floodfill = function (sourcepoint) { - var width = this.paper.width,
- height = this.paper.height,
- ctx = this.paper.getContext("2d"),
- img = ctx.getImageData(0, 0, width, height),
- data = img.data,
- stack = [Math.round(sourcepoint.y) * width + sourcepoint.x],
- currentpoint,
- read,
- sourcecolor,
- checkpoint;
- read = function (p) {
- var d = p * 4;
- return [data[d], data[d + 1], data[d + 2], data[d + 3]];
- };
- sourcecolor = read(stack[0]);
- checkpoint = function (p) {
- return p[0] === sourcecolor[0] &&
- p[1] === sourcecolor[1] &&
- p[2] === sourcecolor[2] &&
- p[3] === sourcecolor[3];
+ var width = this.paper.width, + height = this.paper.height, + ctx = this.paper.getContext("2d"), + img = ctx.getImageData(0, 0, width, height), + data = img.data, + stack = [Math.round(sourcepoint.y) * width + sourcepoint.x], + currentpoint, + read, + sourcecolor, + checkpoint; + read = function (p) { + var d = p * 4; + return [data[d], data[d + 1], data[d + 2], data[d + 3]]; + }; + sourcecolor = read(stack[0]); + checkpoint = function (p) { + return p[0] === sourcecolor[0] && + p[1] === sourcecolor[1] && + p[2] === sourcecolor[2] && + p[3] === sourcecolor[3]; }; // if already filled, abort @@ -690,201 +691,204 @@ PaintCanvasMorph.prototype.floodfill = function (sourcepoint) { } while (stack.length > 0) { - currentpoint = stack.pop();
- if (checkpoint(read(currentpoint))) {
- if (currentpoint % 480 > 1) {
- stack.push(currentpoint + 1);
- stack.push(currentpoint - 1);
- }
- if (currentpoint > 0 && currentpoint < 360 * 480) {
- stack.push(currentpoint + width);
- stack.push(currentpoint - width);
- }
- }
- if (this.settings.primarycolor === "transparent") {
- data[currentpoint * 4 + 3] = 0;
- } else {
- data[currentpoint * 4] = this.settings.primarycolor.r;
- data[currentpoint * 4 + 1] = this.settings.primarycolor.g;
- data[currentpoint * 4 + 2] = this.settings.primarycolor.b;
- data[currentpoint * 4 + 3] = this.settings.primarycolor.a;
- }
- }
+ currentpoint = stack.pop(); + if (checkpoint(read(currentpoint))) { + if (currentpoint % 480 > 1) { + stack.push(currentpoint + 1); + stack.push(currentpoint - 1); + } + if (currentpoint > 0 && currentpoint < 360 * 480) { + stack.push(currentpoint + width); + stack.push(currentpoint - width); + } + } + if (this.settings.primarycolor === "transparent") { + data[currentpoint * 4 + 3] = 0; + } else { + data[currentpoint * 4] = this.settings.primarycolor.r; + data[currentpoint * 4 + 1] = this.settings.primarycolor.g; + data[currentpoint * 4 + 2] = this.settings.primarycolor.b; + data[currentpoint * 4 + 3] = this.settings.primarycolor.a; + } + } ctx.putImageData(img, 0, 0); this.drawNew(); this.changed(); -};
-
-PaintCanvasMorph.prototype.mouseDownLeft = function (pos) {
- this.cacheUndo();
- this.dragRect.origin = pos.subtract(this.bounds.origin);
- this.dragRect.corner = pos.subtract(this.bounds.origin);
- this.previousDragPoint = this.dragRect.corner.copy();
+}; + +PaintCanvasMorph.prototype.mouseDownLeft = function (pos) { + this.cacheUndo(); + this.dragRect.origin = pos.subtract(this.bounds.origin); + this.dragRect.corner = pos.subtract(this.bounds.origin); + this.previousDragPoint = this.dragRect.corner.copy(); if (this.currentTool === 'crosshairs') { this.rotationCenter = pos.subtract(this.bounds.origin); this.drawcrosshair(); return; } - if (this.currentTool === "paintbucket") {
- return this.floodfill(pos.subtract(this.bounds.origin));
- }
- if (this.settings.primarycolor === "transparent" &&
- this.currentTool !== "crosshairs") {
- this.erasermask = newCanvas(this.extent());
- this.merge(this.paper, this.erasermask);
- }
-};
-
+ if (this.currentTool === "paintbucket") { + return this.floodfill(pos.subtract(this.bounds.origin)); + } + if (this.settings.primarycolor === "transparent" && + this.currentTool !== "crosshairs") { + this.erasermask = newCanvas(this.extent()); + this.merge(this.paper, this.erasermask); + } +}; + PaintCanvasMorph.prototype.mouseMove = function (pos) { if (this.currentTool === "paintbucket") { return; } -
- var relpos = pos.subtract(this.bounds.origin),
- mctx = this.mask.getContext("2d"),
- pctx = this.paper.getContext("2d"),
- x = this.dragRect.origin.x, // original drag X
- y = this.dragRect.origin.y, // original drag y
- p = relpos.x, // current drag x
- q = relpos.y, // current drag y
- w = (p - x) / 2, // half the rect width
- h = (q - y) / 2, // half the rect height
- i; // iterator number
- mctx.save();
- function newW() {
- return Math.max(Math.abs(w), Math.abs(h)) * (w / Math.abs(w));
- }
- function newH() {
- return Math.max(Math.abs(w), Math.abs(h)) * (h / Math.abs(h));
- }
- this.brushBuffer.push([p, q]);
- mctx.lineWidth = this.settings.linewidth;
- mctx.clearRect(0, 0, this.bounds.width(), this.bounds.height()); // mask
-
- this.dragRect.corner = relpos.subtract(this.dragRect.origin); // reset crn
-
- if (this.settings.primarycolor === "transparent" &&
- this.currentTool !== "crosshairs") {
- this.merge(this.erasermask, this.mask);
- pctx.clearRect(0, 0, this.bounds.width(), this.bounds.height());
- mctx.globalCompositeOperation = "destination-out";
- } else {
- mctx.fillStyle = this.settings.primarycolor.toString();
- mctx.strokeStyle = this.settings.primarycolor.toString();
- }
- switch (this.currentTool) {
- case "rectangle":
- if (this.isShiftPressed()) {
- mctx.strokeRect(x, y, newW() * 2, newH() * 2);
- } else {
- mctx.strokeRect(x, y, w * 2, h * 2);
- }
- break;
- case "rectangleSolid":
- if (this.isShiftPressed()) {
- mctx.fillRect(x, y, newW() * 2, newH() * 2);
- } else {
- mctx.fillRect(x, y, w * 2, h * 2);
- }
- break;
- case "brush":
- mctx.lineCap = "round";
- mctx.lineJoin = "round";
- mctx.beginPath();
- mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
- for (i = 0; i < this.brushBuffer.length; i += 1) {
- mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
- }
- mctx.stroke();
- break;
- case "line":
- mctx.beginPath();
- mctx.moveTo(x, y);
- if (this.isShiftPressed()) {
- if (Math.abs(h) > Math.abs(w)) {
- mctx.lineTo(x, q);
- } else {
- mctx.lineTo(p, y);
- }
- } else {
- mctx.lineTo(p, q);
- }
- mctx.stroke();
- break;
- case "circle":
- case "circleSolid":
- mctx.beginPath();
- if (this.isShiftPressed()) {
- mctx.arc(
- x,
- y,
- new Point(x, y).distanceTo(new Point(p, q)),
- 0,
- Math.PI * 2,
- false
- );
- } else {
- for (i = 0; i < 480; i += 1) {
- mctx.lineTo(
- i,
- (2 * h) * Math.sqrt(2 - Math.pow(
- (i - x) / (2 * w),
- 2
- )) + y
- );
- }
- for (i = 480; i > 0; i -= 1) {
- mctx.lineTo(
- i,
- -1 * (2 * h) * Math.sqrt(2 - Math.pow(
- (i - x) / (2 * w),
- 2
- )) + y
- );
- }
- }
- mctx.closePath();
- if (this.currentTool === "circleSolid") {
- mctx.fill();
- } else {
- if (this.currentTool === "circle") {
- mctx.stroke();
- }
- }
- break;
+ + var relpos = pos.subtract(this.bounds.origin), + mctx = this.mask.getContext("2d"), + pctx = this.paper.getContext("2d"), + x = this.dragRect.origin.x, // original drag X + y = this.dragRect.origin.y, // original drag y + p = relpos.x, // current drag x + q = relpos.y, // current drag y + w = (p - x) / 2, // half the rect width + h = (q - y) / 2, // half the rect height + i; // iterator number + mctx.save(); + function newW() { + return Math.max(Math.abs(w), Math.abs(h)) * (w / Math.abs(w)); + } + function newH() { + return Math.max(Math.abs(w), Math.abs(h)) * (h / Math.abs(h)); + } + this.brushBuffer.push([p, q]); + mctx.lineWidth = this.settings.linewidth; + mctx.clearRect(0, 0, this.bounds.width(), this.bounds.height()); // mask + + this.dragRect.corner = relpos.subtract(this.dragRect.origin); // reset crn + + if (this.settings.primarycolor === "transparent" && + this.currentTool !== "crosshairs") { + this.merge(this.erasermask, this.mask); + pctx.clearRect(0, 0, this.bounds.width(), this.bounds.height()); + mctx.globalCompositeOperation = "destination-out"; + } else { + mctx.fillStyle = this.settings.primarycolor.toString(); + mctx.strokeStyle = this.settings.primarycolor.toString(); + } + switch (this.currentTool) { + case "rectangle": + if (this.isShiftPressed()) { + mctx.strokeRect(x, y, newW() * 2, newH() * 2); + } else { + mctx.strokeRect(x, y, w * 2, h * 2); + } + break; + case "rectangleSolid": + if (this.isShiftPressed()) { + mctx.fillRect(x, y, newW() * 2, newH() * 2); + } else { + mctx.fillRect(x, y, w * 2, h * 2); + } + break; + case "brush": + mctx.lineCap = "round"; + mctx.lineJoin = "round"; + mctx.beginPath(); + mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]); + for (i = 0; i < this.brushBuffer.length; i += 1) { + mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]); + } + mctx.stroke(); + break; + case "line": + mctx.beginPath(); + mctx.moveTo(x, y); + if (this.isShiftPressed()) { + if (Math.abs(h) > Math.abs(w)) { + mctx.lineTo(x, q); + } else { + mctx.lineTo(p, y); + } + } else { + mctx.lineTo(p, q); + } + mctx.stroke(); + break; + case "circle": + case "circleSolid": + mctx.beginPath(); + if (this.isShiftPressed()) { + mctx.arc( + x, + y, + new Point(x, y).distanceTo(new Point(p, q)), + 0, + Math.PI * 2, + false + ); + } else { + for (i = 0; i < 480; i += 1) { + mctx.lineTo( + i, + (2 * h) * Math.sqrt(2 - Math.pow( + (i - x) / (2 * w), + 2 + )) + y + ); + } + for (i = 480; i > 0; i -= 1) { + mctx.lineTo( + i, + -1 * (2 * h) * Math.sqrt(2 - Math.pow( + (i - x) / (2 * w), + 2 + )) + y + ); + } + } + mctx.closePath(); + if (this.currentTool === "circleSolid") { + mctx.fill(); + } else { + if (this.currentTool === "circle") { + mctx.stroke(); + } + } + break; case "crosshairs": this.rotationCenter = relpos.copy(); this.drawcrosshair(mctx); - break;
- case "eraser":
- this.merge(this.paper, this.mask);
- mctx.save();
- mctx.globalCompositeOperation = "destination-out";
- mctx.beginPath();
- mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
- for (i = 0; i < this.brushBuffer.length; i += 1) {
- mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
- }
- mctx.stroke();
- mctx.restore();
- this.paper = newCanvas(this.extent());
- this.merge(this.mask, this.paper);
- break;
- default:
- nop();
- }
- this.previousDragPoint = relpos;
- this.drawNew();
- this.changed();
- mctx.restore();
-};
-
+ break; + case "eraser": + this.merge(this.paper, this.mask); + mctx.save(); + mctx.globalCompositeOperation = "destination-out"; + mctx.beginPath(); + mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]); + for (i = 0; i < this.brushBuffer.length; i += 1) { + mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]); + } + mctx.stroke(); + mctx.restore(); + this.paper = newCanvas(this.extent()); + this.merge(this.mask, this.paper); + break; + default: + nop(); + } + this.previousDragPoint = relpos; + this.drawNew(); + this.changed(); + mctx.restore(); +}; + PaintCanvasMorph.prototype.mouseClickLeft = function () { - if (this.currentTool !== "crosshairs") {
- this.merge(this.mask, this.paper);
- }
- this.brushBuffer = [];
-};
+ if (this.currentTool !== "crosshairs") { + this.merge(this.mask, this.paper); + } + this.brushBuffer = []; +}; + +PaintCanvasMorph.prototype.mouseLeaveDragging + = PaintCanvasMorph.prototype.mouseClickLeft; PaintCanvasMorph.prototype.buildContents = function () { this.background = newCanvas(this.extent()); @@ -903,47 +907,47 @@ PaintCanvasMorph.prototype.buildContents = function () { } } }; -
-PaintCanvasMorph.prototype.drawNew = function () {
- var can = newCanvas(this.extent());
- this.merge(this.background, can);
- this.merge(this.paper, can);
- this.merge(this.mask, can);
- this.image = can;
- this.drawFrame();
-};
-
-PaintCanvasMorph.prototype.drawFrame = function () {
- var context, borderColor;
-
- context = this.image.getContext('2d');
- if (this.parent) {
- this.color = this.parent.color.lighter(this.contrast * 0.75);
- borderColor = this.parent.color;
- } else {
- borderColor = new Color(120, 120, 120);
- }
- context.fillStyle = this.color.toString();
-
- // cache my border colors
- this.cachedClr = borderColor.toString();
- this.cachedClrBright = borderColor.lighter(this.contrast)
- .toString();
- this.cachedClrDark = borderColor.darker(this.contrast).toString();
- this.drawRectBorder(context);
-};
-
-PaintCanvasMorph.prototype.drawRectBorder
- = InputFieldMorph.prototype.drawRectBorder;
-
-PaintCanvasMorph.prototype.edge
- = InputFieldMorph.prototype.edge;
-
-PaintCanvasMorph.prototype.fontSize
- = InputFieldMorph.prototype.fontSize;
-
-PaintCanvasMorph.prototype.typeInPadding
- = InputFieldMorph.prototype.typeInPadding;
-
-PaintCanvasMorph.prototype.contrast
- = InputFieldMorph.prototype.contrast;
+ +PaintCanvasMorph.prototype.drawNew = function () { + var can = newCanvas(this.extent()); + this.merge(this.background, can); + this.merge(this.paper, can); + this.merge(this.mask, can); + this.image = can; + this.drawFrame(); +}; + +PaintCanvasMorph.prototype.drawFrame = function () { + var context, borderColor; + + context = this.image.getContext('2d'); + if (this.parent) { + this.color = this.parent.color.lighter(this.contrast * 0.75); + borderColor = this.parent.color; + } else { + borderColor = new Color(120, 120, 120); + } + context.fillStyle = this.color.toString(); + + // cache my border colors + this.cachedClr = borderColor.toString(); + this.cachedClrBright = borderColor.lighter(this.contrast) + .toString(); + this.cachedClrDark = borderColor.darker(this.contrast).toString(); + this.drawRectBorder(context); +}; + +PaintCanvasMorph.prototype.drawRectBorder + = InputFieldMorph.prototype.drawRectBorder; + +PaintCanvasMorph.prototype.edge + = InputFieldMorph.prototype.edge; + +PaintCanvasMorph.prototype.fontSize + = InputFieldMorph.prototype.fontSize; + +PaintCanvasMorph.prototype.typeInPadding + = InputFieldMorph.prototype.typeInPadding; + +PaintCanvasMorph.prototype.contrast + = InputFieldMorph.prototype.contrast; @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -61,7 +61,7 @@ SyntaxElementMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2013-December-19'; +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'), @@ -9,7 +9,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/ // Global stuff //////////////////////////////////////////////////////// -modules.threads = '2014-January-26'; +modules.threads = '2014-Feb-03'; var ThreadManager; var Process; @@ -151,15 +151,19 @@ ThreadManager.prototype.startProcess = function (block, isThreadSafe) { return newProc; }; -ThreadManager.prototype.stopAll = function () { +ThreadManager.prototype.stopAll = function (excpt) { + // excpt is optional this.processes.forEach(function (proc) { - proc.stop(); + if (proc !== excpt) { + proc.stop(); + } }); }; -ThreadManager.prototype.stopAllForReceiver = function (rcvr) { +ThreadManager.prototype.stopAllForReceiver = function (rcvr, excpt) { + // excpt is optional this.processes.forEach(function (proc) { - if (proc.homeContext.receiver === rcvr) { + if (proc.homeContext.receiver === rcvr && proc !== excpt) { proc.stop(); if (rcvr.isClone) { proc.isDead = true; @@ -1368,6 +1372,44 @@ Process.prototype.doStopAll = function () { } }; +Process.prototype.doStopThis = function (choice) { + switch (this.inputOption(choice)) { + case 'all': + this.doStopAll(); + break; + case 'this script': + this.doStop(); + break; + case 'this block': + this.doStopBlock(); + break; + default: + nop(); + } +}; + +Process.prototype.doStopOthers = function (choice) { + var stage; + if (this.homeContext.receiver) { + stage = this.homeContext.receiver.parentThatIsA(StageMorph); + if (stage) { + switch (this.inputOption(choice)) { + case 'all but this script': + stage.threads.stopAll(this); + break; + case 'other scripts in sprite': + stage.threads.stopAllForReceiver( + this.homeContext.receiver, + this + ); + break; + default: + nop(); + } + } + } +}; + Process.prototype.doWarp = function (body) { // execute my contents block atomically (more or less) var outer = this.context.outerContext, // for tail call elimination @@ -1601,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, @@ -1624,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'); @@ -1637,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) { @@ -1681,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) { @@ -1691,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) { @@ -1711,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; } } @@ -2246,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); @@ -2342,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, @@ -2365,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; @@ -2377,6 +2424,9 @@ Process.prototype.reportAttributeOf = function (attribute, name) { thatObj = this.getOtherObject(name, thisObj, stage); } if (thatObj) { + if (attribute instanceof Context) { + return this.reportContextFor(attribute, thatObj); + } if (isString(attribute)) { return thatObj.variables.getVar(attribute); } @@ -2401,6 +2451,18 @@ Process.prototype.reportAttributeOf = function (attribute, name) { return ''; }; +Process.prototype.reportContextFor = function (context, otherObj) { + // Private - return a copy of the context + // and bind it to another receiver + var result = copy(context); + result.receiver = otherObj; + if (result.outerContext) { + result.outerContext = copy(result.outerContext); + result.outerContext.receiver = otherObj; + } + return result; +}; + Process.prototype.reportMouseX = function () { var stage, world; if (this.homeContext.receiver) { @@ -2492,12 +2554,12 @@ Process.prototype.reportDate = function (datefn) { currDate = new Date(); func = dateMap[datefn]; result = currDate[func](); - + // Show months as 1-12 and days as 1-7 if (datefn === 'month' || datefn === 'day of week') { result += 1; } - + return result; } @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph, ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences, ScrollFrameMorph*/ -modules.widgets = '2013-November-26'; +modules.widgets = '2014-January-09'; var PushButtonMorph; var ToggleButtonMorph; @@ -7,7 +7,7 @@ written by Jens Mönig jens@moenig.org - Copyright (C) 2013 by Jens Mönig + Copyright (C) 2014 by Jens Mönig This file is part of Snap!. @@ -65,7 +65,7 @@ // Global stuff //////////////////////////////////////////////////////// -modules.xml = '2013-April-19'; +modules.xml = '2014-January-09'; // Declarations @@ -90,13 +90,15 @@ ReadStream.prototype.space = /[\s]/; // ReadStream accessing: ReadStream.prototype.next = function (count) { - var element; + var element, start; if (count === undefined) { element = this.contents[this.index]; this.index += 1; return element; } - return this.contents.slice(this.index, this.index += count); + start = this.index; + this.index += count; + return this.contents.slice(start, this.index); }; ReadStream.prototype.peek = function () { @@ -114,12 +116,15 @@ ReadStream.prototype.atEnd = function () { // ReadStream accessing String contents: ReadStream.prototype.upTo = function (regex) { + var i, start; if (!isString(this.contents)) {return ''; } - var i = this.contents.substr(this.index).search(regex); + i = this.contents.substr(this.index).search(regex); if (i === -1) { return ''; } - return this.contents.substring(this.index, this.index += i); + start = this.index; + this.index += i; + return this.contents.substring(start, this.index); }; ReadStream.prototype.peekUpTo = function (regex) { @@ -133,19 +138,23 @@ ReadStream.prototype.peekUpTo = function (regex) { ReadStream.prototype.skipSpace = function () { if (!isString(this.contents)) {return ''; } - var ch; - while (this.space.test(ch = this.peek()) && ch !== '') { + var ch = this.peek(); + while (this.space.test(ch) && ch !== '') { this.skip(); + ch = this.peek(); } }; ReadStream.prototype.word = function () { + var i, start; if (!isString(this.contents)) {return ''; } - var i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/); + i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/); if (i === -1) { return ''; } - return this.contents.substring(this.index, this.index += i); + start = this.index; + this.index += i; + return this.contents.substring(start, this.index); }; // XML_Element /////////////////////////////////////////////////////////// @@ -376,14 +385,16 @@ XML_Element.prototype.parseStream = function (stream) { stream.skipSpace(); // attributes: - while ((ch = stream.peek()) !== '>' && ch !== '/') { + ch = stream.peek(); + while (ch !== '>' && ch !== '/') { key = stream.word(); stream.skipSpace(); if (stream.next() !== '=') { throw new Error('Expected "=" after attribute name'); } stream.skipSpace(); - if ((ch = stream.next()) !== '"' && ch !== "'") { + ch = stream.next(); + if (ch !== '"' && ch !== "'") { throw new Error( 'Expected single- or double-quoted attribute value' ); @@ -392,6 +403,7 @@ XML_Element.prototype.parseStream = function (stream) { stream.skip(1); stream.skipSpace(); this.attributes[key] = this.unescape(value); + ch = stream.peek(); } // empty tag: |
