diff options
| -rw-r--r-- | Backgrounds/atom-playground.jpg | bin | 0 -> 77018 bytes | |||
| -rw-r--r-- | Backgrounds/bedroom1.gif | bin | 0 -> 27694 bytes | |||
| -rw-r--r-- | Backgrounds/bedroom2.gif | bin | 0 -> 23267 bytes | |||
| -rw-r--r-- | Backgrounds/berkeley-mural.jpg | bin | 0 -> 98720 bytes | |||
| -rw-r--r-- | Backgrounds/brick-wall-and-stairs.jpg | bin | 0 -> 110521 bytes | |||
| -rw-r--r-- | Backgrounds/brick-wall1.jpg | bin | 0 -> 41872 bytes | |||
| -rw-r--r-- | Backgrounds/brick-wall2.jpg | bin | 0 -> 109096 bytes | |||
| -rw-r--r-- | Backgrounds/desert.gif | bin | 0 -> 34344 bytes | |||
| -rw-r--r-- | Backgrounds/night-city-with-street.gif | bin | 0 -> 20496 bytes | |||
| -rw-r--r-- | Backgrounds/party-room.jpg | bin | 0 -> 31708 bytes | |||
| -rw-r--r-- | Backgrounds/pathway.jpg | bin | 0 -> 113122 bytes | |||
| -rw-r--r-- | Backgrounds/xy-grid.gif | bin | 0 -> 4135 bytes | |||
| -rw-r--r-- | Costumes/alonzo.gif | bin | 0 -> 1587 bytes | |||
| -rw-r--r-- | Costumes/bat1-a.png | bin | 0 -> 4907 bytes | |||
| -rw-r--r-- | Costumes/bat1-b.png | bin | 0 -> 4572 bytes | |||
| -rw-r--r-- | Costumes/bat2-a.png | bin | 0 -> 2171 bytes | |||
| -rw-r--r-- | Costumes/bat2-b.png | bin | 0 -> 2237 bytes | |||
| -rw-r--r-- | Costumes/boy1-standing.gif | bin | 0 -> 6041 bytes | |||
| -rw-r--r-- | Costumes/boy1-walking.gif | bin | 0 -> 4925 bytes | |||
| -rw-r--r-- | Costumes/boy2.gif | bin | 0 -> 4764 bytes | |||
| -rw-r--r-- | Costumes/boy3.gif | bin | 0 -> 4410 bytes | |||
| -rw-r--r-- | Costumes/cat2.gif | bin | 0 -> 1681 bytes | |||
| -rw-r--r-- | Costumes/cat3.png | bin | 0 -> 4253 bytes | |||
| -rw-r--r-- | Costumes/cat4.png | bin | 0 -> 4607 bytes | |||
| -rw-r--r-- | Costumes/cat5.gif | bin | 0 -> 5761 bytes | |||
| -rw-r--r-- | Costumes/dog1-a.png | bin | 0 -> 2709 bytes | |||
| -rw-r--r-- | Costumes/dog1-b.png | bin | 0 -> 2849 bytes | |||
| -rw-r--r-- | Costumes/dog2-a.png | bin | 0 -> 3173 bytes | |||
| -rw-r--r-- | Costumes/dog2-b.png | bin | 0 -> 2952 bytes | |||
| -rw-r--r-- | Costumes/dog2-c.png | bin | 0 -> 3002 bytes | |||
| -rw-r--r-- | Costumes/dragon1-a.png | bin | 0 -> 3078 bytes | |||
| -rw-r--r-- | Costumes/dragon1-b.png | bin | 0 -> 3421 bytes | |||
| -rw-r--r-- | Costumes/dragon2.gif | bin | 0 -> 2591 bytes | |||
| -rw-r--r-- | Costumes/girl1-standing.gif | bin | 0 -> 1364 bytes | |||
| -rw-r--r-- | Costumes/girl1-walking.gif | bin | 0 -> 1569 bytes | |||
| -rw-r--r-- | Costumes/girl2-shouting.gif | bin | 0 -> 1584 bytes | |||
| -rw-r--r-- | Costumes/girl2-standing.gif | bin | 0 -> 1475 bytes | |||
| -rw-r--r-- | Costumes/girl3-basketball.gif | bin | 0 -> 6585 bytes | |||
| -rw-r--r-- | Costumes/girl3-running.gif | bin | 0 -> 5837 bytes | |||
| -rw-r--r-- | Costumes/girl3-standing.gif | bin | 0 -> 1514 bytes | |||
| -rw-r--r-- | Costumes/marissa-crouching.gif | bin | 0 -> 9955 bytes | |||
| -rw-r--r-- | Costumes/marissa-sitting.gif | bin | 0 -> 7855 bytes | |||
| -rw-r--r-- | Costumes/marissa.gif | bin | 0 -> 9210 bytes | |||
| -rw-r--r-- | Costumes/unicorn1.png | bin | 0 -> 4648 bytes | |||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | Sounds/Cat.mp3 | bin | 0 -> 8194 bytes | |||
| -rw-r--r-- | Sounds/Chord.wav | bin | 0 -> 41260 bytes | |||
| -rw-r--r-- | Sounds/Dog1.wav | bin | 0 -> 7388 bytes | |||
| -rw-r--r-- | Sounds/Dog2.wav | bin | 0 -> 6380 bytes | |||
| -rw-r--r-- | Sounds/FingerSnap.wav | bin | 0 -> 4014 bytes | |||
| -rw-r--r-- | Sounds/Kitten.wav | bin | 0 -> 37420 bytes | |||
| -rw-r--r-- | Sounds/Laugh-female.wav | bin | 0 -> 27138 bytes | |||
| -rw-r--r-- | Sounds/Laugh-male1.wav | bin | 0 -> 29368 bytes | |||
| -rw-r--r-- | Sounds/Laugh-male2.wav | bin | 0 -> 64174 bytes | |||
| -rw-r--r-- | Sounds/Laugh-male3.mp3 | bin | 0 -> 30137 bytes | |||
| -rw-r--r-- | Sounds/Meow.wav | bin | 0 -> 13068 bytes | |||
| -rw-r--r-- | Sounds/Pop.wav | bin | 0 -> 1076 bytes | |||
| -rw-r--r-- | blocks.js | 68 | ||||
| -rw-r--r-- | byob.js | 10 | ||||
| -rw-r--r-- | cloud.js | 7 | ||||
| -rw-r--r-- | gui.js | 177 | ||||
| -rwxr-xr-x | history.txt | 65 | ||||
| -rw-r--r-- | lang-de.js | 42 | ||||
| -rw-r--r-- | lang-fi.js | 1280 | ||||
| -rw-r--r-- | lang-fr.js | 6 | ||||
| -rwxr-xr-x | lang-pt.js | 26 | ||||
| -rwxr-xr-x | lang-pt_BR.js | 1389 | ||||
| -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 | 37 | ||||
| -rw-r--r-- | morphic.js | 13 | ||||
| -rw-r--r-- | objects.js | 188 | ||||
| -rw-r--r-- | paint.js | 1433 | ||||
| -rw-r--r-- | store.js | 22 | ||||
| -rw-r--r-- | threads.js | 133 | ||||
| -rw-r--r-- | widgets.js | 111 | ||||
| -rw-r--r-- | xml.js | 36 |
82 files changed, 4231 insertions, 828 deletions
diff --git a/Backgrounds/atom-playground.jpg b/Backgrounds/atom-playground.jpg Binary files differnew file mode 100644 index 0000000..94b953e --- /dev/null +++ b/Backgrounds/atom-playground.jpg diff --git a/Backgrounds/bedroom1.gif b/Backgrounds/bedroom1.gif Binary files differnew file mode 100644 index 0000000..17b23a3 --- /dev/null +++ b/Backgrounds/bedroom1.gif diff --git a/Backgrounds/bedroom2.gif b/Backgrounds/bedroom2.gif Binary files differnew file mode 100644 index 0000000..9e14bab --- /dev/null +++ b/Backgrounds/bedroom2.gif diff --git a/Backgrounds/berkeley-mural.jpg b/Backgrounds/berkeley-mural.jpg Binary files differnew file mode 100644 index 0000000..2df7a43 --- /dev/null +++ b/Backgrounds/berkeley-mural.jpg diff --git a/Backgrounds/brick-wall-and-stairs.jpg b/Backgrounds/brick-wall-and-stairs.jpg Binary files differnew file mode 100644 index 0000000..78e412d --- /dev/null +++ b/Backgrounds/brick-wall-and-stairs.jpg diff --git a/Backgrounds/brick-wall1.jpg b/Backgrounds/brick-wall1.jpg Binary files differnew file mode 100644 index 0000000..e3e76ef --- /dev/null +++ b/Backgrounds/brick-wall1.jpg diff --git a/Backgrounds/brick-wall2.jpg b/Backgrounds/brick-wall2.jpg Binary files differnew file mode 100644 index 0000000..da4d56b --- /dev/null +++ b/Backgrounds/brick-wall2.jpg diff --git a/Backgrounds/desert.gif b/Backgrounds/desert.gif Binary files differnew file mode 100644 index 0000000..16769b3 --- /dev/null +++ b/Backgrounds/desert.gif diff --git a/Backgrounds/night-city-with-street.gif b/Backgrounds/night-city-with-street.gif Binary files differnew file mode 100644 index 0000000..91e6185 --- /dev/null +++ b/Backgrounds/night-city-with-street.gif diff --git a/Backgrounds/party-room.jpg b/Backgrounds/party-room.jpg Binary files differnew file mode 100644 index 0000000..f253c9f --- /dev/null +++ b/Backgrounds/party-room.jpg diff --git a/Backgrounds/pathway.jpg b/Backgrounds/pathway.jpg Binary files differnew file mode 100644 index 0000000..03d5235 --- /dev/null +++ b/Backgrounds/pathway.jpg diff --git a/Backgrounds/xy-grid.gif b/Backgrounds/xy-grid.gif Binary files differnew file mode 100644 index 0000000..9e46216 --- /dev/null +++ b/Backgrounds/xy-grid.gif diff --git a/Costumes/alonzo.gif b/Costumes/alonzo.gif Binary files differnew file mode 100644 index 0000000..ce53a4f --- /dev/null +++ b/Costumes/alonzo.gif diff --git a/Costumes/bat1-a.png b/Costumes/bat1-a.png Binary files differnew file mode 100644 index 0000000..8d3af1e --- /dev/null +++ b/Costumes/bat1-a.png diff --git a/Costumes/bat1-b.png b/Costumes/bat1-b.png Binary files differnew file mode 100644 index 0000000..bb309df --- /dev/null +++ b/Costumes/bat1-b.png diff --git a/Costumes/bat2-a.png b/Costumes/bat2-a.png Binary files differnew file mode 100644 index 0000000..c97a6be --- /dev/null +++ b/Costumes/bat2-a.png diff --git a/Costumes/bat2-b.png b/Costumes/bat2-b.png Binary files differnew file mode 100644 index 0000000..c5cb521 --- /dev/null +++ b/Costumes/bat2-b.png diff --git a/Costumes/boy1-standing.gif b/Costumes/boy1-standing.gif Binary files differnew file mode 100644 index 0000000..a560af4 --- /dev/null +++ b/Costumes/boy1-standing.gif diff --git a/Costumes/boy1-walking.gif b/Costumes/boy1-walking.gif Binary files differnew file mode 100644 index 0000000..3772b00 --- /dev/null +++ b/Costumes/boy1-walking.gif diff --git a/Costumes/boy2.gif b/Costumes/boy2.gif Binary files differnew file mode 100644 index 0000000..58d9221 --- /dev/null +++ b/Costumes/boy2.gif diff --git a/Costumes/boy3.gif b/Costumes/boy3.gif Binary files differnew file mode 100644 index 0000000..ee076e8 --- /dev/null +++ b/Costumes/boy3.gif diff --git a/Costumes/cat2.gif b/Costumes/cat2.gif Binary files differnew file mode 100644 index 0000000..e9c0785 --- /dev/null +++ b/Costumes/cat2.gif diff --git a/Costumes/cat3.png b/Costumes/cat3.png Binary files differnew file mode 100644 index 0000000..d03b3f4 --- /dev/null +++ b/Costumes/cat3.png diff --git a/Costumes/cat4.png b/Costumes/cat4.png Binary files differnew file mode 100644 index 0000000..02f379a --- /dev/null +++ b/Costumes/cat4.png diff --git a/Costumes/cat5.gif b/Costumes/cat5.gif Binary files differnew file mode 100644 index 0000000..6ebd3af --- /dev/null +++ b/Costumes/cat5.gif diff --git a/Costumes/dog1-a.png b/Costumes/dog1-a.png Binary files differnew file mode 100644 index 0000000..69f8ef3 --- /dev/null +++ b/Costumes/dog1-a.png diff --git a/Costumes/dog1-b.png b/Costumes/dog1-b.png Binary files differnew file mode 100644 index 0000000..fd592e3 --- /dev/null +++ b/Costumes/dog1-b.png diff --git a/Costumes/dog2-a.png b/Costumes/dog2-a.png Binary files differnew file mode 100644 index 0000000..bbb29eb --- /dev/null +++ b/Costumes/dog2-a.png diff --git a/Costumes/dog2-b.png b/Costumes/dog2-b.png Binary files differnew file mode 100644 index 0000000..9279cdc --- /dev/null +++ b/Costumes/dog2-b.png diff --git a/Costumes/dog2-c.png b/Costumes/dog2-c.png Binary files differnew file mode 100644 index 0000000..6b314d2 --- /dev/null +++ b/Costumes/dog2-c.png diff --git a/Costumes/dragon1-a.png b/Costumes/dragon1-a.png Binary files differnew file mode 100644 index 0000000..c216eea --- /dev/null +++ b/Costumes/dragon1-a.png diff --git a/Costumes/dragon1-b.png b/Costumes/dragon1-b.png Binary files differnew file mode 100644 index 0000000..83261c5 --- /dev/null +++ b/Costumes/dragon1-b.png diff --git a/Costumes/dragon2.gif b/Costumes/dragon2.gif Binary files differnew file mode 100644 index 0000000..d63305d --- /dev/null +++ b/Costumes/dragon2.gif diff --git a/Costumes/girl1-standing.gif b/Costumes/girl1-standing.gif Binary files differnew file mode 100644 index 0000000..60369d0 --- /dev/null +++ b/Costumes/girl1-standing.gif diff --git a/Costumes/girl1-walking.gif b/Costumes/girl1-walking.gif Binary files differnew file mode 100644 index 0000000..e7bad2b --- /dev/null +++ b/Costumes/girl1-walking.gif diff --git a/Costumes/girl2-shouting.gif b/Costumes/girl2-shouting.gif Binary files differnew file mode 100644 index 0000000..783b636 --- /dev/null +++ b/Costumes/girl2-shouting.gif diff --git a/Costumes/girl2-standing.gif b/Costumes/girl2-standing.gif Binary files differnew file mode 100644 index 0000000..6550406 --- /dev/null +++ b/Costumes/girl2-standing.gif diff --git a/Costumes/girl3-basketball.gif b/Costumes/girl3-basketball.gif Binary files differnew file mode 100644 index 0000000..1a7f330 --- /dev/null +++ b/Costumes/girl3-basketball.gif diff --git a/Costumes/girl3-running.gif b/Costumes/girl3-running.gif Binary files differnew file mode 100644 index 0000000..abdc510 --- /dev/null +++ b/Costumes/girl3-running.gif diff --git a/Costumes/girl3-standing.gif b/Costumes/girl3-standing.gif Binary files differnew file mode 100644 index 0000000..fec700b --- /dev/null +++ b/Costumes/girl3-standing.gif diff --git a/Costumes/marissa-crouching.gif b/Costumes/marissa-crouching.gif Binary files differnew file mode 100644 index 0000000..7bbf4b0 --- /dev/null +++ b/Costumes/marissa-crouching.gif diff --git a/Costumes/marissa-sitting.gif b/Costumes/marissa-sitting.gif Binary files differnew file mode 100644 index 0000000..500ce97 --- /dev/null +++ b/Costumes/marissa-sitting.gif diff --git a/Costumes/marissa.gif b/Costumes/marissa.gif Binary files differnew file mode 100644 index 0000000..bdebc84 --- /dev/null +++ b/Costumes/marissa.gif diff --git a/Costumes/unicorn1.png b/Costumes/unicorn1.png Binary files differnew file mode 100644 index 0000000..eb3b870 --- /dev/null +++ b/Costumes/unicorn1.png @@ -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 diff --git a/Sounds/Cat.mp3 b/Sounds/Cat.mp3 Binary files differnew file mode 100644 index 0000000..e65fdca --- /dev/null +++ b/Sounds/Cat.mp3 diff --git a/Sounds/Chord.wav b/Sounds/Chord.wav Binary files differnew file mode 100644 index 0000000..838ff3a --- /dev/null +++ b/Sounds/Chord.wav diff --git a/Sounds/Dog1.wav b/Sounds/Dog1.wav Binary files differnew file mode 100644 index 0000000..1cbdbcc --- /dev/null +++ b/Sounds/Dog1.wav diff --git a/Sounds/Dog2.wav b/Sounds/Dog2.wav Binary files differnew file mode 100644 index 0000000..68e024c --- /dev/null +++ b/Sounds/Dog2.wav diff --git a/Sounds/FingerSnap.wav b/Sounds/FingerSnap.wav Binary files differnew file mode 100644 index 0000000..df56220 --- /dev/null +++ b/Sounds/FingerSnap.wav diff --git a/Sounds/Kitten.wav b/Sounds/Kitten.wav Binary files differnew file mode 100644 index 0000000..45742d5 --- /dev/null +++ b/Sounds/Kitten.wav diff --git a/Sounds/Laugh-female.wav b/Sounds/Laugh-female.wav Binary files differnew file mode 100644 index 0000000..7784804 --- /dev/null +++ b/Sounds/Laugh-female.wav diff --git a/Sounds/Laugh-male1.wav b/Sounds/Laugh-male1.wav Binary files differnew file mode 100644 index 0000000..191e3b7 --- /dev/null +++ b/Sounds/Laugh-male1.wav diff --git a/Sounds/Laugh-male2.wav b/Sounds/Laugh-male2.wav Binary files differnew file mode 100644 index 0000000..2ab8921 --- /dev/null +++ b/Sounds/Laugh-male2.wav diff --git a/Sounds/Laugh-male3.mp3 b/Sounds/Laugh-male3.mp3 Binary files differnew file mode 100644 index 0000000..f6f22c7 --- /dev/null +++ b/Sounds/Laugh-male3.mp3 diff --git a/Sounds/Meow.wav b/Sounds/Meow.wav Binary files differnew file mode 100644 index 0000000..a07a948 --- /dev/null +++ b/Sounds/Meow.wav diff --git a/Sounds/Pop.wav b/Sounds/Pop.wav Binary files differnew file mode 100644 index 0000000..60bdf1d --- /dev/null +++ b/Sounds/Pop.wav @@ -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-November-26'; +modules.blocks = '2014-March-31'; + var SyntaxElementMorph; var BlockMorph; @@ -812,6 +813,24 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { true // read-only ); break; + case '%dates': + part = new InputSlotMorph( + null, // text + false, // non-numeric + { + 'year' : ['year'], + 'month' : ['month'], + 'date' : ['date'], + 'day of week' : ['day of week'], + 'hour' : ['hour'], + 'minute' : ['minute'], + 'second' : ['second'], + 'time in milliseconds' : ['time in milliseconds'] + }, + true // read-only + ); + part.setContents(['date']); + break; case '%delim': part = new InputSlotMorph( null, // text @@ -996,7 +1015,6 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { 'attributesMenu', true ); - part.isStatic = true; break; case '%fun': part = new InputSlotMorph( @@ -1038,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, @@ -1166,7 +1211,6 @@ SyntaxElementMorph.prototype.labelPart = function (spec) { ); break; - // symbols: case '%turtle': @@ -1591,6 +1635,12 @@ SyntaxElementMorph.prototype.showBubble = function (value) { morphToShow.silentSetWidth(img.width); morphToShow.silentSetHeight(img.height); morphToShow.image = img; + } else if (value instanceof Costume) { + img = value.thumbnail(new Point(40, 40)); + morphToShow = new Morph(); + morphToShow.silentSetWidth(img.width); + morphToShow.silentSetHeight(img.height); + morphToShow.image = img; } else if (value instanceof Context) { img = value.image(); morphToShow = new Morph(); @@ -3267,6 +3317,7 @@ CommandBlockMorph.prototype.snap = function () { CommandBlockMorph.prototype.isStop = function () { return ([ + 'doStopThis', 'doStop', 'doStopBlock', 'doStopAll', @@ -6147,7 +6198,7 @@ CSlotMorph.prototype.drawBottomEdge = function (context) { I am an editable text input slot. I can be either rectangular or rounded, and can have an optional drop-down menu. If I'm set to read-only I must have a drop-down menu and will assume a darker - shade of my parent's color. + shade of my parent's color. my most important public attributes and accessors are: @@ -6302,6 +6353,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]); } @@ -6518,6 +6571,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-13'; // Declarations @@ -1447,7 +1447,8 @@ IDE_Morph.prototype.setProjectName = function (string) { // IDE_Morph resizing IDE_Morph.prototype.setExtent = function (point) { - var minExt, + var padding = new Point(430, 110), + minExt, ext; // determine the minimum dimensions making sense for the current mode @@ -1463,7 +1464,12 @@ IDE_Morph.prototype.setExtent = function (point) { } */ minExt = this.isSmallStage ? + padding.add(StageMorph.prototype.dimensions.divideBy(2)) + : padding.add(StageMorph.prototype.dimensions); +/* + minExt = this.isSmallStage ? new Point(700, 350) : new Point(910, 490); +*/ } ext = point.max(minExt); IDE_Morph.uber.setExtent.call(this, ext); @@ -2061,6 +2067,10 @@ IDE_Morph.prototype.settingsMenu = function () { 'Zoom blocks...', 'userSetBlocksScale' ); + menu.addItem( + 'Stage size...', + 'userSetStageSize' + ); menu.addLine(); addPreference( 'Blurred shadows', @@ -2212,6 +2222,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 +2253,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 +2402,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 +2498,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' @@ -2598,10 +2705,12 @@ IDE_Morph.prototype.newProject = function () { this.globalVariables = new VariableFrame(); this.currentSprite = new SpriteMorph(this.globalVariables); this.sprites = new List([this.currentSprite]); + StageMorph.prototype.dimensions = new Point(480, 360); StageMorph.prototype.hiddenPrimitives = {}; StageMorph.prototype.codeMappings = {}; StageMorph.prototype.codeHeaders = {}; StageMorph.prototype.enableCodeMapping = false; + SpriteMorph.prototype.useFlatLineEnds = false; this.setProjectName(''); this.projectNotes = ''; this.createStage(); @@ -3366,6 +3475,64 @@ IDE_Morph.prototype.setBlocksScale = function (num) { this.saveSetting('zoom', num); }; +// IDE_Morph stage size manipulation + +IDE_Morph.prototype.userSetStageSize = function () { + new DialogBoxMorph( + this, + this.setStageExtent, + this + ).promptVector( + "Stage size", + StageMorph.prototype.dimensions, + new Point(480, 360), + 'Stage width', + 'Stage height', + this.world(), + null, // pic + null // msg + ); +}; + +IDE_Morph.prototype.setStageExtent = function (aPoint) { + var myself = this, + world = this.world(), + ext = aPoint.max(new Point(480, 180)); + + function zoom() { + myself.step = function () { + var delta = ext.subtract( + StageMorph.prototype.dimensions + ).divideBy(2); + if (delta.abs().lt(new Point(5, 5))) { + StageMorph.prototype.dimensions = ext; + delete myself.step; + } else { + StageMorph.prototype.dimensions = + StageMorph.prototype.dimensions.add(delta); + } + myself.stage.setExtent(StageMorph.prototype.dimensions); + myself.stage.clearPenTrails(); + myself.fixLayout(); + this.setExtent(world.extent()); + }; + } + + this.stageRatio = 1; + this.isSmallStage = false; + this.controlBar.stageSizeButton.refresh(); + this.setExtent(world.extent()); + if (this.isAnimating) { + zoom(); + } else { + StageMorph.prototype.dimensions = ext; + this.stage.setExtent(StageMorph.prototype.dimensions); + this.stage.clearPenTrails(); + this.fixLayout(); + this.setExtent(world.extent()); + } +}; + // IDE_Morph cloud interface IDE_Morph.prototype.initializeCloud = function () { diff --git a/history.txt b/history.txt index 642ea7f..2c0362b 100755 --- a/history.txt +++ b/history.txt @@ -2044,3 +2044,68 @@ ______ ------ * 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! + +140205 +------ +* Objects, Paint: One-stop-shopping for stage dimensions (changing the stage dimensions in line 3720 of objects.js takes care of everything) + +140211 +------ +* GUI: Set stage dimensions arbitrarily (new entries in the settings menu when holding shift) +* Store: Saving & Loading for arbitrary stage dimensions in the project data +* new Date block, thanks, Michael!!! + +140213 +------ +* GUI, Store: constrain minimum stage size to 480 x 180 +* GUI: Fixed #322, #324 +* Widgets: new “promptVector” dialog box feature +* GUI: Use new vector prompter for stage dimensions +* German translation update + +140331 +------ +* Objects: experimental “wardrobe” and “jukebox” reporters in dev mode +* Blocks, Objects: display costume thumbnails in speech/thought/value bubbles and watcher cells +* Objects: let “switch to costume” block accept actual costume objects (in addition to names and numbers) @@ -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-13', // 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': @@ -677,6 +685,16 @@ SnapTranslator.dict.de = { 'Sprache...', 'Zoom blocks...': 'Bl\u00f6cke vergr\u00f6\u00dfern...', + 'Stage size...': + 'B\u00fchnengr\u00f6\u00dfe...', + 'Stage size': + 'B\u00fchnengr\u00f6\u00dfe', + 'Stage width': + 'B\u00fchnenbreite', + 'Stage height': + 'B\u00fchnenh\u00f6he', + 'Default': + 'Normal', 'Blurred shadows': 'Weiche Schatten', 'uncheck to use solid drop\nshadows and highlights': @@ -759,6 +777,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 +974,6 @@ SnapTranslator.dict.de = { 'in diesem Projekt gibt es noch keine\nglobalen Bl\u00f6cke', 'select': 'ausw\u00e4hlen', - 'all': - 'alles', 'none': 'nichts', diff --git a/lang-fi.js b/lang-fi.js new file mode 100644 index 0000000..bb70a9f --- /dev/null +++ b/lang-fi.js @@ -0,0 +1,1280 @@ +/* + + lang-fi.js + + Finnish translation for SNAP! + + written by Jouni K. Seppänen + + Copyright (C) 2014 by Jens Mönig + + 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 + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + + + Note to Translators: + -------------------- + At this stage of development, Snap! can be translated to any LTR language + maintaining the current order of inputs (formal parameters in blocks). + + Translating Snap! is easy: + + + 1. Download + + Download the sources and extract them into a local folder on your + computer: + + <http://snap.berkeley.edu/snapsource/snap.zip> + + Use the German translation file (named 'lang-de.js') as template for your + own translations. Start with editing the original file, because that way + you will be able to immediately check the results in your browsers while + you're working on your translation (keep the local copy of snap.html open + in your web browser, and refresh it as you progress with your + translation). + + + 2. Edit + + Edit the translation file with a regular text editor, or with your + favorite JavaScript editor. + + In the first non-commented line (the one right below this + note) replace "de" with the two-letter ISO 639-1 code for your language, + e.g. + + fr - French => SnapTranslator.dict.fr = { + it - Italian => SnapTranslator.dict.it = { + pl - Polish => SnapTranslator.dict.pl = { + pt - Portuguese => SnapTranslator.dict.pt = { + es - Spanish => SnapTranslator.dict.es = { + el - Greek => => SnapTranslator.dict.el = { + + etc. (see <http://en.wikipedia.org/wiki/ISO_639-1>) + + + 3. Translate + + Then work through the dictionary, replacing the German strings against + your translations. The dictionary is a straight-forward JavaScript ad-hoc + object, for review purposes it should be formatted as follows: + + { + 'English string': + 'Translation string', + 'last key': + } 'last value' + + and you only edit the indented value strings. Note that each key-value + pair needs to be delimited by a comma, but that there shouldn't be a comma + after the last pair (again, just overwrite the template file and you'll be + fine). + + If something doesn't work, or if you're unsure about the formalities you + should check your file with + + <http://JSLint.com> + + This will inform you about any missed commas etc. + + + 4. Accented characters + + Depending on which text editor and which file encoding you use you can + directly enter special characters (e.g. Umlaut, accented characters) on + your keyboard. However, I've noticed that some browsers may not display + special characters correctly, even if other browsers do. So it's best to + check your results in several browsers. If you want to be on the safe + side, it's even better to escape these characters using Unicode. + + see: <http://0xcc.net/jsescape/> + + + 5. Block specs: + + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + + + 6. Submit + + When you're done, rename the edited file by replacing the "de" part of the + filename with the two-letter ISO 639-1 code for your language, e.g. + + fr - French => lang-fr.js + it - Italian => lang-it.js + pl - Polish => lang-pl.js + pt - Portuguese => lang-pt.js + es - Spanish => lang-es.js + el - Greek => => lang-el.js + + and send it to me for inclusion in the official Snap! distribution. + Once your translation has been included, Your name will the shown in the + "Translators" tab in the "About Snap!" dialog box, and you will be able to + directly launch a translated version of Snap! in your browser by appending + + lang:xx + + to the URL, xx representing your translations two-letter code. + + + 7. Known issues + + In some browsers accents or ornaments located in typographic ascenders + above the cap height are currently (partially) cut-off. + + Enjoy! + -Jens +*/ + +/*global SnapTranslator*/ + +SnapTranslator.dict.fi = { + +/* + Special characters: (see <http://0xcc.net/jsescape/>) + + Ä, ä \u00c4, \u00e4 + Ö, ö \u00d6, \u00f6 + → \u2192 + \u200B zero-width space, useful to escape % at the beginning of words +*/ + + // translations meta information + 'language_name': + 'suomi', // the name as it should appear in the language menu + 'language_translator': + 'Jouni K. Sepp\u00e4nen', // your name for the Translators tab + 'translator_e-mail': + 'jks@iki.fi', // optional + 'last_changed': + '2014-04-18', // this, too, will appear in the Translators tab + + // GUI + // control bar: + 'untitled': + 'nimet\u00f6n', + 'development mode': + 'kehitysmoodi', + + // categories: + 'Motion': + 'Liike', + 'Looks': + 'Ulkon\u00e4k\u00f6', + 'Sound': + '\u00c4\u00e4ni', + 'Pen': + 'Kyn\u00e4', + 'Control': + 'Ohjaus', + 'Sensing': + 'Tuntoaisti', + 'Operators': + 'Laskenta', + 'Variables': + 'Muuttujat', + 'Lists': + 'Listat', + 'Other': + 'Muut', + + // editor: + 'draggable': + 'hiirell\u00e4 liikuteltava', + + // tabs: + 'Scripts': + 'Skriptit', + 'Costumes': + 'Asut', + 'Sounds': + '\u00c4\u00e4net', + + // names: + 'Sprite': + 'Hahmo', + 'Stage': + 'Esiintymislava', + + // rotation styles: + 'don\'t rotate': + 'ei py\u00f6ri', + 'can rotate': + 'py\u00f6rii vapaasti', + 'only face left/right': + 'k\u00e4\u00e4ntyy vain vasemmalle ja oikealle', + + // new sprite button: + 'add a new sprite': + 'lis\u00e4\u00e4 uusi hahmo', + + // tab help + 'costumes tab help': + 'Tuo kuva verkosta tai koneeltasi\n' + + 'siirt\u00e4m\u00e4ll\u00e4 se hiirell\u00e4 t\u00e4h\u00e4n', + 'import a sound from your computer\nby dragging it into here': + 'Tuo \u00e4\u00e4ni koneeltasi\n' + + 'siirt\u00e4m\u00e4ll\u00e4 se hiirell\u00e4 t\u00e4h\u00e4n', + + // primitive blocks: + + /* + Attention Translators: + ---------------------- + At this time your translation of block specs will only work + correctly, if the order of formal parameters and their types + are unchanged. Placeholders for inputs (formal parameters) are + indicated by a preceding % prefix and followed by a type + abbreviation. + + For example: + + 'say %s for %n secs' + + can currently not be changed into + + 'say %n secs long %s' + + and still work as intended. + + Similarly + + 'point towards %dst' + + cannot be changed into + + 'point towards %cst' + + without breaking its functionality. + */ + + // motion: + 'Stage selected:\nno motion primitives': + 'Esiintymislava valittuna\nei liikekomentoja', + + 'move %n steps': + 'liiku %n askelta', + 'turn %clockwise %n degrees': + 'k\u00e4\u00e4nny %clockwise %n astetta', + 'turn %counterclockwise %n degrees': + 'k\u00e4\u00e4nny %counterclockwise %n astetta', + 'point in direction %dir': + 'osoita suuntaan %dir', + 'point towards %dst': + 'osoita hahmoa %dst kohti', + 'go to x: %n y: %n': + 'mene paikkaan x: %n y: %n', + 'go to %dst': + 'mene hahmon %dst luo', + 'glide %n secs to x: %n y: %n': + 'liu\'u %n s \u2192 x: %n y: %n', + 'change x by %n': + 'muuta x:\u00e4\u00e4 %n askelta', + 'set x to %n': + 'aseta x:ksi %n', + 'change y by %n': + 'muuta y:t\u00e4 %n askelta', + 'set y to %n': + 'aseta y:ksi %n', + 'if on edge, bounce': + 'kimpoa reunasta', + 'x position': + 'x-paikka', + 'y position': + 'y-paikka', + 'direction': + 'suunta', + + // looks: + 'switch to costume %cst': + 'vaihda asuun %cst', + 'next costume': + 'seuraava asu', + 'costume #': + 'asun nro', + 'say %s for %n secs': + 'sano %s %n sekunnin ajan', + 'say %s': + 'sano %s', + 'think %s for %n secs': + 'ajattele %s %n sekunnin ajan', + 'think %s': + 'ajattele %s', + 'Hello!': + 'Hei!', + 'Hmm...': + 'Hmm...', + 'change %eff effect by %n': + 'muuta efekti\u00e4 %eff %n yksikk\u00f6\u00e4', + 'set %eff effect to %n': + 'aseta efektin %eff m\u00e4\u00e4r\u00e4ksi %n', + 'clear graphic effects': + 'poista efektit', + 'change size by %n': + // using a zero-width space to hide % at word beginning + 'muuta kokoa %n \u200B%-yksikk\u00f6\u00e4', + 'set size to %n %': + 'aseta kooksi %n %', + 'size': + 'koko', + 'show': + 'n\u00e4yt\u00e4', + 'hide': + 'piilota', + 'go to front': + 'tule etualalle', + 'go back %n layers': + 'siirry %n kerrosta taakse', + + 'development mode \ndebugging primitives:': + 'Kehitysmoodin \ndebuggauskomennot:', + 'console log %mult%s': + 'kirjoita konsoliin: %mult%s', + 'alert %mult%s': + 'ponnahdusikkuna: %mult%s', + + // sound: + 'play sound %snd': + 'soita \u00e4\u00e4ni %snd', + 'play sound %snd until done': + 'soita \u00e4\u00e4ni %snd kokonaan', + 'stop all sounds': + 'pys\u00e4yt\u00e4 kaikki \u00e4\u00e4net', + 'rest for %n beats': + 'tauko %n iskua', + 'play note %n for %n beats': + 'nuotti %n %n iskua', + 'change tempo by %n': + 'vaihda tempoa %n iskulla/min', + 'set tempo to %n bpm': + 'aseta tempoksi %n iskua/min', + 'tempo': + 'tempo', + + // pen: + 'clear': + 'tyhjenn\u00e4', + 'pen down': + 'kyn\u00e4 alas', + 'pen up': + 'kyn\u00e4 yl\u00f6s', + 'set pen color to %clr': + 'aseta kyn\u00e4n v\u00e4riksi %clr', + 'change pen color by %n': + 'vaihda kyn\u00e4n v\u00e4ri\u00e4 m\u00e4\u00e4r\u00e4ll\u00e4 %n', + 'set pen color to %n': + 'aseta kyn\u00e4n v\u00e4riksi %n', + 'change pen shade by %n': + // using a zero-width space to hide % at word beginning + 'muuta kirkkautta %n \u200b%-yks.', + 'set pen shade to %n': + 'aseta kirkkaudeksi %n %', + 'change pen size by %n': + 'muuta paksuutta m\u00e4\u00e4r\u00e4ll\u00e4 %n', + 'set pen size to %n': + 'aseta kyn\u00e4n paksuudeksi %n', + 'stamp': + 'leimaa', + + // control: + 'when %greenflag clicked': + 'kun klikataan %greenflag', + 'when %keyHat key pressed': + 'kun painetaan %keyHat', + 'when I am clicked': + 'kun minua klikataan', + 'when I receive %msgHat': + 'kun vastaanotan sanoman %msgHat', + 'broadcast %msg': + 'l\u00e4het\u00e4 sanoma %msg', + 'broadcast %msg and wait': + 'l\u00e4het\u00e4 sanoma %msg ja odota', + 'Message name': + 'Sanoma', + 'message': + 'sanoma', + 'any message': + 'mik\u00e4 tahansa', + 'wait %n secs': + 'odota %n sekuntia', + 'wait until %b': + 'odota kunnes %b', + 'forever %c': + 'ikuisesti %c', + 'repeat %n %c': + 'toista %n kertaa %c', + 'repeat until %b %c': + 'toista kunnes %b %c', + 'if %b %c': + 'jos %b %c', + 'if %b %c else %c': + 'jos %b %c muuten %c', + 'report %s': + 'vastaa %s', + 'stop %stopChoices': + 'pys\u00e4yt\u00e4 %stopChoices', + 'all': + 'kaikki', + 'this script': + 't\u00e4m\u00e4 skripti', + 'this block': + 't\u00e4m\u00e4 palikka', + 'stop %stopOthersChoices': + 'pys\u00e4yt\u00e4 %stopOthersChoices', + 'all but this script': + 'kaikki paitsi t\u00e4m\u00e4 skripti', + 'other scripts in sprite': + 'hahmon muut skriptit', + 'pause all %pause': + 'keskeyt\u00e4 kaikki %pause', + 'run %cmdRing %inputs': + 'suorita %cmdRing %inputs', + 'launch %cmdRing %inputs': + 'k\u00e4ynnist\u00e4 %cmdRing %inputs', + 'call %repRing %inputs': + 'kutsu %repRing %inputs', + 'run %cmdRing w/continuation': + 'suorita %cmdRing kontinuaatiolla', + 'call %cmdRing w/continuation': + 'kutsu %cmdRing kontinuaatiolla', + 'warp %c': + 'supernopeasti %c', + 'when I start as a clone': + 'Kun aloitan kloonina', + 'create a clone of %cln': + 'kloonaa %cln', + 'myself': + 'minut', + 'delete this clone': + 'poista t\u00e4m\u00e4 klooni', + + // sensing: + 'touching %col ?': + 'koskettaa hahmoa %col ?', + 'touching %clr ?': + 'koskettaa v\u00e4ri\u00e4 %clr ?', + 'color %clr is touching %clr ?': + 'v\u00e4ri %clr koskettaa v\u00e4ri\u00e4 %clr ?', + 'ask %s and wait': + 'kysy %s ja odota', + 'what\'s your name?': + 'Mik\u00e4 sinun nimesi on?', + 'answer': + 'vastaus', + 'mouse x': + 'hiiren x-paikka', + 'mouse y': + 'hiiren y-paikka', + 'mouse down?': + 'hiiren n\u00e4pp\u00e4in painettuna?', + 'key %key pressed?': + 'n\u00e4pp\u00e4in %key painettuna?', + 'distance to %dst': + 'et\u00e4isyys hahmoon %dst', + 'reset timer': + 'nollaa ajastin', + 'timer': + 'ajastin', + '%att of %spr': + '%att hahmolla %spr', + 'http:// %s': + 'http:// %s', + 'turbo mode?': + 'turbonopeus?', + 'set turbo mode to %b': + 'kytke turbonopeus p\u00e4\u00e4lle jos %b', + + 'filtered for %clr': + 'suodatettuna v\u00e4ri %clr', + 'stack size': + 'pinon koko', + 'frames': + 'ruutuja', + + // operators: + '%n mod %n': + 'jakoj\u00e4\u00e4nn\u00f6s laskusta %n / %n', + 'round %n': + 'py\u00f6rist\u00e4 %n', + '%fun of %n': + '%fun %n', + 'pick random %n to %n': + 'arvo satunnaisluku %n .. %n', + '%b and %b': + '%b ja %b', + '%b or %b': + '%b tai %b', + 'not %b': + 'ei %b', + 'true': + 'tosi', + 'false': + 'ep\u00e4tosi', + 'join %words': + 'yhdist\u00e4 %words', + 'split %s by %delim': + 'pilko %s %delim kohdalta', + 'hello': + 'Hei', + 'world': + 'maailma', + 'letter %n of %s': + 'kirjain nro %n tekstist\u00e4 %s', + 'length of %s': + 'tekstin %s pituus', + 'unicode of %s': + 'merkin %s Unicode-arvo', + 'unicode %n as letter': + 'Unicode-arvoa %n vastaava merkki', + 'is %s a %typ ?': + 'onko %s %typ ?', + 'is %s identical to %s ?': + 'onko %s sama kuin %s ?', + + 'type of %s': + '%s:n tyyppi', + + // variables: + 'Make a variable': + 'Uusi muuttuja', + 'Variable name': + 'Muuttujan nimi', + 'Script variable name': + 'Skriptimuuttujan nimi', + 'Delete a variable': + 'poista muuttuja', + + 'set %var to %s': + 'aseta muuttujan %var arvoksi %s', + 'change %var by %n': + 'muuta muuttujaa %var m\u00e4\u00e4r\u00e4ll\u00e4 %n', + 'show variable %var': + 'n\u00e4yt\u00e4 muuttuja %var', + 'hide variable %var': + 'piilota muuttuja %var', + 'script variables %scriptVars': + 'skriptimuuttujat %scriptVars', + + // lists: + 'list %exp': + 'lista %exp', + '%s in front of %l': + '%s listan %l aluksi', + 'item %idx of %l': + 'alkio kohdassa %idx listassa %l', + 'all but first of %l': + 'kaikki paitsi ensimm\u00e4inen alkio listasta %l', + 'length of %l': + 'listan %l pituus', + '%l contains %s': + 'lista %l sis\u00e4lt\u00e4\u00e4 %s', + 'thing': + 'alkio', + 'add %s to %l': + 'lis\u00e4\u00e4 %s listaan %l', + 'delete %ida of %l': + 'poista %ida listasta %l', + 'insert %s at %idx of %l': + 'lis\u00e4\u00e4 %s kohtaan %idx listassa %l', + 'replace item %idx of %l with %s': + 'vaihda kohtaan %idx listassa %l alkio %s', + + // other + 'Make a block': + 'Uusi palikka', + + // menus + // snap menu + 'About...': + 'Tietoa Snapista...', + 'Reference manual': + 'K\u00e4ytt\u00f6ohje', + 'Snap! website': + 'Snapin kotisivu', + 'Download source': + 'Lataa l\u00e4hdekoodi', + 'Switch back to user mode': + 'Palaa k\u00e4ytt\u00e4j\u00e4moodiin', + 'disable deep-Morphic\ncontext menus\nand show user-friendly ones': + 'poista Morphic-valikot k\u00e4yt\u00f6st\u00e4\n' + + 'ja n\u00e4yt\u00e4 helpot valikot', + 'Switch to dev mode': + 'vaihda kehitysmoodiin', + 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!': + 'n\u00e4yt\u00e4 Morphic-toiminnot,\n' + + 'ei kovin helppok\u00e4ytt\u00f6isi\u00e4', + + // project menu + 'Project notes...': + 'Projektimerkint\u00f6j\u00e4...', + 'New': + 'Uusi', + 'Open...': + 'Avaa...', + 'Save': + 'Tallenna', + 'Save As...': + 'Tallenna nimell\u00e4...', + 'Import...': + 'Tuo...', + 'file menu import hint': + 'lataa viety projekti,\npalikkakirjasto, asu\ntai \u00e4\u00e4ni', + 'Export project as plain text...': + 'Vie projekti tekstin\u00e4...', + 'Export project...': + 'Vie projekti...', + 'show project data as XML\nin a new browser window': + 'n\u00e4yt\u00e4 projekti XML-muodossa\nuudessa selainikkunassa', + 'Export blocks...': + 'Vie palikoita...', + 'show global custom block definitions as XML\nin a new browser window': + 'n\u00e4yt\u00e4 yhteiset palikkam\u00e4\u00e4rittelyt\n' + + 'XML-muodossa uudessa selainikkunassa', + 'Import tools': + 'Tuo ty\u00f6kaluja', + 'load the official library of\npowerful blocks': + 'lataa virallinen tehopalikoiden kirjasto', + 'Libraries...': + 'Kirjastot...', + 'Import library': + 'Tuo kirjasto', + + // cloud menu + 'Login...': + 'Kirjaudu...', + 'Signup...': + 'Luo k\u00e4ytt\u00e4j\u00e4tili...', + + // settings menu + 'Language...': + 'Kieli...', + 'Zoom blocks...': + 'Suurenna palikoita...', + 'Stage size...': + 'Esiintymislavan koko...', + 'Stage size': + 'Esiintymislavan koko', + 'Stage width': + 'Esiintymislavan leveys', + 'Stage height': + 'Esiintymislavan korkeus', + 'Default': + 'Tavallinen', + 'Blurred shadows': + 'Sumeat varjot', + 'uncheck to use solid drop\nshadows and highlights': + 'poistamalla saat kiinte\u00e4t varjot\nja korostukset', + 'check to use blurred drop\nshadows and highlights': + 'asettamalla saat sumeat varjot\nja korostukset', + 'Zebra coloring': + 'Seeprav\u00e4ritys', + 'check to enable alternating\ncolors for nested blocks': + 'asettamalla saat vaihtuvat v\u00e4rit\nsis\u00e4kk\u00e4isille palikoille', + 'uncheck to disable alternating\ncolors for nested block': + 'poistamalla saat samat v\u00e4rit\nsis\u00e4kk\u00e4isille palikoille', + 'Dynamic input labels': + 'Vaihtuvat sy\u00f6tetunnukset', + 'uncheck to disable dynamic\nlabels for variadic inputs': + 'poistamalla est\u00e4t vaihtuvien\nsy\u00f6tteiden vaihtuvat tunnukset', + 'check to enable dynamic\nlabels for variadic inputs': + 'asettamalla saat vaihtuville\nsy\u00f6tteille vaihtuvat tunnukset', + 'Prefer empty slot drops': + 'Suosi asettamista tyhjiin aukkoihin', + 'settings menu prefer empty slots hint': + 'asettamalla saat asetettavat\npalikat osumaan tyhjiin aukkoihin', + 'uncheck to allow dropped\nreporters to kick out others': + 'poistamalla sallit asetettujen\npalikoiden pois potkimisen', + 'Long form input dialog': + 'Yksityiskohtainen sy\u00f6tevalinta', + 'Plain prototype labels': + 'Yksinkertaiset palikkatunnisteet', + 'uncheck to always show (+) symbols\nin block prototype labels': + 'poistamalla saat (+)-merkit\nn\u00e4kym\u00e4\u00e4n aina\n' + + 'palikan muokkauksessa', + 'check to hide (+) symbols\nin block prototype labels': + 'asettamalla piilotat (+)-merkit\npalikan muokkauksessa', + 'check to always show slot\ntypes in the input dialog': + 'asettamalla n\u00e4et aina\ntietotyyppivalinnat\n' + + 'palikan sy\u00f6tteit\u00e4 lis\u00e4tess\u00e4', + 'uncheck to use the input\ndialog in short form': + 'poistamalla teet palikan\nsy\u00f6tteiden lis\u00e4\u00e4misikkunasta\n' + + 'yksinkertaisen', + 'Virtual keyboard': + 'Virtuaalin\u00e4pp\u00e4imist\u00f6', + 'uncheck to disable\nvirtual keyboard support\nfor mobile devices': + 'poistamalla est\u00e4t mobiililaitteiden\n' + + 'virtuaalin\u00e4pp\u00e4imist\u00f6n k\u00e4yt\u00f6n', + 'check to enable\nvirtual keyboard support\nfor mobile devices': + 'asettamalla sallit mobiililaitteiden\n' + + 'virtuaalin\u00e4pp\u00e4imist\u00f6n k\u00e4yt\u00f6n', + 'Input sliders': + 'Liukus\u00e4\u00e4timet', + 'uncheck to disable\ninput sliders for\nentry fields': + 'poistamalla piilotat\nliukus\u00e4\u00e4timet sy\u00f6tekentist\u00e4\n', + 'check to enable\ninput sliders for\nentry fields': + 'asettamalla saat\nsy\u00f6tekenttiin liukus\u00e4\u00e4timet', + 'Clicking sound': + 'Klikkaus\u00e4\u00e4ni', + 'uncheck to turn\nblock clicking\nsound off': + 'poistamalla hiljenn\u00e4t\npalikoiden klikkaus\u00e4\u00e4nen', + 'check to turn\nblock clicking\nsound on': + 'asettamalla kytket p\u00e4\u00e4lle\npalikoiden klikkaus\u00e4\u00e4nen', + 'Animations': + 'Animaatiot', + 'uncheck to disable\nIDE animations': + 'poistamalla piilotat\nk\u00e4ytt\u00f6liittym\u00e4n animaatiot', + 'Turbo mode': + 'Turbonopeus', + 'check to prioritize\nscript execution': + 'asettamalla nostat\nskriptien prioriteettia', + 'uncheck to run scripts\nat normal speed': + 'poistamalla ajat\nskriptit normaalinopeudella', + 'check to enable\nIDE animations': + 'asettamalla kytket p\u00e4\u00e4lle\n' + + 'k\u00e4ytt\u00f6liittym\u00e4n animaatiot', + 'Thread safe scripts': + 'S\u00e4ieturvalliset skriptit', + 'uncheck to allow\nscript reentrance': + 'poistamalla sallit skriptin\nk\u00e4ynnistymisen vaikka se on ajossa', + 'check to disallow\nscript reentrance': + 'asettamalla est\u00e4t skriptin\nk\u00e4ynnistymisen jos se on jo ajossa', + 'Prefer smooth animations': + 'Pyri sulaviin animaatioihin', + 'uncheck for greater speed\nat variable frame rates': + 'poistamalla saat lis\u00e4\u00e4 nopeutta\n' + + 'mutta p\u00e4ivitystaajuus vaihtelee', + 'check for smooth, predictable\nanimations across computers': + 'asettamalla saat sulavat\nanimaatiot eri tietokoneilla', + 'Flat line ends': + 'Tasaiset viivanp\u00e4\u00e4t', + 'check for flat ends of lines': + 'asettamalla saat viivan p\u00e4ist\u00e4 suorat', + 'uncheck for round ends of lines': + 'poistamalla saat viivan p\u00e4ist\u00e4 py\u00f6ristetyt', + + // inputs + 'with inputs': + 'sy\u00f6tteill\u00e4', + 'input names:': + 'sy\u00f6tteet:', + 'Input Names:': + 'Sy\u00f6tteet:', + 'input list:': + 'sy\u00f6telista:', + + // context menus: + 'help': + 'apua', + + // palette: + 'hide primitives': + 'piilota peruspalikat', + 'show primitives': + 'n\u00e4yt\u00e4 peruspalikat', + + // blocks: + 'help...': + 'apua...', + 'relabel...': + 'nime\u00e4 uudestaan...', + 'duplicate': + 'kopioi', + 'make a copy\nand pick it up': + 'ota kopio mukaan', + 'only duplicate this block': + 'kopioi vain t\u00e4m\u00e4 palikka', + 'delete': + 'poista', + 'script pic...': + 'kuva skriptist\u00e4...', + 'open a new window\nwith a picture of this script': + 'avaa kuva t\u00e4st\u00e4 skriptist\u00e4\nuudessa selainikkunassa', + 'ringify': + 'ympyr\u00f6i', + 'unringify': + 'poista ympyr\u00f6inti', + + // custom blocks: + 'delete block definition...': + 'poista palikkam\u00e4\u00e4rittely', + 'edit...': + 'muokkaa...', + + // sprites: + 'edit': + 'muokkaa', + 'detach from': + 'irrota', + 'detach all parts': + 'irrota kaikki osat', + 'export...': + 'Vie...', + + // stage: + 'show all': + 'N\u00e4yt\u00e4 kaikki', + 'pic...': + 'Vie kuva...', + 'open a new window\nwith a picture of the stage': + 'Avaa esiintymislavan kuva\nuuteen selainikkunaan', + + // scripting area + 'clean up': + 'siivoa', + 'arrange scripts\nvertically': + 'j\u00e4rjest\u00e4 pystysuorasti', + 'add comment': + 'lis\u00e4\u00e4 kommentti', + 'undrop': + 'peruuta asetus', + 'undo the last\nblock drop\nin this pane': + 'peruuta viimeisin\npalikan asetus', + 'scripts pic...': + 'kuva skripteist\u00e4...', + 'open a new window\nwith a picture of all scripts': + 'avaa kuva\nkaikista skripteist\u00e4\nuudessa selainikkunassa', + 'make a block...': + 'tee uusi palikka...', + + // costumes + 'rename': + 'nime\u00e4 uudestaan', + 'export': + 'vie', + 'rename costume': + 'nime\u00e4 asu uudestaan', + + // sounds + 'Play sound': + 'Soita \u00e4\u00e4ni', + 'Stop sound': + 'Pys\u00e4yt\u00e4 \u00e4\u00e4ni', + 'Stop': + 'Pys\u00e4yt\u00e4', + 'Play': + 'Soita', + 'rename sound': + 'nime\u00e4 \u00e4\u00e4ni uudestaan', + + // dialogs + // buttons + 'OK': + 'OK', + 'Ok': + 'OK', + 'Cancel': + 'Peruuta', + 'Yes': + 'Kyll\u00e4', + 'No': + 'Ei', + + // help + 'Help': + 'Apua', + + // zoom blocks + 'Zoom blocks': + 'Suurenna palikoita', + 'build': + 'rakenna', + 'your own': + 'omia', + 'blocks': + 'palikoita', + 'normal (1x)': + 'normaali (1x)', + 'demo (1.2x)': + 'demo (1.2x)', + 'presentation (1.4x)': + 'esitys (1.4x)', + 'big (2x)': + 'iso (2x)', + 'huge (4x)': + 'valtava (4x)', + 'giant (8x)': + 'j\u00e4ttim\u00e4inen (8x)', + 'monstrous (10x)': + 'hirvi\u00f6m\u00e4inen (10x)', + + // Project Manager + 'Untitled': + 'Nimet\u00f6n', + 'Open Project': + 'Avaa projekti', + '(empty)': + '(tyhj\u00e4)', + 'Saved!': + 'Tallennettu!', + 'Delete Project': + 'Poista projekti', + 'Are you sure you want to delete': + 'Poistetaanko varmasti?', + 'rename...': + 'nime\u00e4 uusiksi...', + + // costume editor + 'Costume Editor': + 'Asun muokkaus', + 'click or drag crosshairs to move the rotation center': + 'siirr\u00e4 kiertokeskusta klikkaamalla\n' + + 'tai pit\u00e4m\u00e4ll\u00e4 hiirt\u00e4 ' + + 'painettuna ja liikuttamalla', + + // project notes + 'Project Notes': + 'Projektin muistiinpanot', + + // new project + 'New Project': + 'Uusi projekti', + 'Replace the current project with a new one?': + 'Korvataanko nykyinen projekti uudella?', + + // save project + 'Save Project As...': + 'Tallenna projekti nimell\u00e4...', + + // export blocks + 'Export blocks': + 'Vie palikoita', + 'Import blocks': + 'Tuo palikoita', + 'this project doesn\'t have any\ncustom global blocks yet': + 'projektilla ei ole viel\u00e4\nyht\u00e4\u00e4n yhteist\u00e4\n' + + 'muokattua palikkaa', + 'select': + 'valitse', + 'none': + 'ei mit\u00e4\u00e4n', + + // variable dialog + 'for all sprites': + 'kaikille hahmoille', + 'for this sprite only': + 'vain t\u00e4lle hahmolle', + + // block dialog + 'Change block': + 'Muuta palikkaa', + 'Command': + 'Komento', + 'Reporter': + 'Funktio', + 'Predicate': + 'Predikaatti', + + // block editor + 'Block Editor': + 'Palikan muokkaus', + 'Apply': + 'Tee muutokset', + + // block deletion dialog + 'Delete Custom Block': + 'Poista palikka', + 'block deletion dialog text': + 'Poistetaanko t\u00e4m\u00e4 palikka\n ja kaikki sen esiintym\u00e4t?', + + + // input dialog + 'Create input name': + 'Nime\u00e4 sy\u00f6te', + 'Edit input name': + 'Muokkaa sy\u00f6tteen nime\u00e4', + 'Edit label fragment': + 'Muokkaa otsikkoa', + 'Title text': + 'Otsikko', + 'Input name': + 'Sy\u00f6te', + 'Delete': + 'Poista', + 'Object': + 'Objekti', + 'Number': + 'Luku', + 'Text': + 'Teksti', + 'List': + 'Lista', + 'Any type': + 'Mik\u00e4 vain', + 'Boolean (T/F)': + 'Totuusarvo', + 'Command\n(inline)': + 'Komento', + 'Command\n(C-shape)': + 'Komento\n(C-muoto)', + 'Any\n(unevaluated)': + 'Mik\u00e4 vain\n(sitaatti)', + 'Boolean\n(unevaluated)': + 'Totuusarvo\n(sitaatti)', + 'Single input.': + 'Yksi sy\u00f6te.', + 'Default Value:': + 'Oletusarvo:', + 'Multiple inputs (value is list of inputs)': + 'Useita sy\u00f6tteit\u00e4 (listana)', + 'Upvar - make internal variable visible to caller': + 'Paljasta sis\u00e4inen muuttuja ulkopuolelle', + + // About Snap + 'About Snap': + 'Tietoa Snapista', + 'Back...': + 'Takaisin...', + 'License...': + 'Tekij\u00e4noikeudet...', + 'Modules...': + 'Osat...', + 'Credits...': + 'Kiitokset...', + 'Translators...': + 'K\u00e4\u00e4nt\u00e4j\u00e4t...', + 'License': + 'Tekij\u00e4noikeudet', + 'current module versions:': + 'Osien versiot:', + 'Contributors': + 'Osallistujat', + 'Translations': + 'K\u00e4\u00e4nn\u00f6kset', + + // variable watchers + 'normal': + 'tavallinen', + 'large': + 'suuri', + 'slider': + 'liukus\u00e4\u00e4din', + 'slider min...': + 'minimiarvo...', + 'slider max...': + 'maksimiarvo...', + 'import...': + 'tuo...', + 'Slider minimum value': + 'Liukus\u00e4\u00e4timen minimiarvo', + 'Slider maximum value': + 'Liukus\u00e4\u00e4timen maksimiarvo', + + // list watchers + 'length: ': + 'pituus: ', + + // coments + 'add comment here...': + 'Kirjoita kommentti t\u00e4h\u00e4n...', + + // drow downs + // directions + '(90) right': + '(90) oikealle', + '(-90) left': + '(-90) vasemmalle', + '(0) up': + '(0) yl\u00f6s', + '(180) down': + '(180) alas', + + // collision detection + 'mouse-pointer': + 'hiiren osoitin', + 'edge': + 'reuna', + 'pen trails': + 'kyn\u00e4n j\u00e4lki', + + // costumes + 'Turtle': + 'Osoitin', + 'Empty': + 'Tyhj\u00e4', + + // graphical effects + 'ghost': + 'l\u00e4pin\u00e4kyvyys', + + // keys + 'space': + 'v\u00e4lily\u00f6nti', + 'up arrow': + 'nuoli yl\u00f6s', + 'down arrow': + 'nuoli alas', + 'right arrow': + 'nuoli oikealle', + 'left arrow': + 'nuoli vasemmalle', + 'a': + 'a', + 'b': + 'b', + 'c': + 'c', + 'd': + 'd', + 'e': + 'e', + 'f': + 'f', + 'g': + 'g', + 'h': + 'h', + 'i': + 'i', + 'j': + 'j', + 'k': + 'k', + 'l': + 'l', + 'm': + 'm', + 'n': + 'n', + 'o': + 'o', + 'p': + 'p', + 'q': + 'q', + 'r': + 'r', + 's': + 's', + 't': + 't', + 'u': + 'u', + 'v': + 'v', + 'w': + 'w', + 'x': + 'x', + 'y': + 'y', + 'z': + 'z', + '0': + '0', + '1': + '1', + '2': + '2', + '3': + '3', + '4': + '4', + '5': + '5', + '6': + '6', + '7': + '7', + '8': + '8', + '9': + '9', + + // messages + 'new...': + 'uusi...', + + // math functions + 'abs': + 'itseisarvo', + 'floor': + 'py\u00f6ristys alas', + 'sqrt': + 'neli\u00f6juuri', + 'sin': + 'sin', + 'cos': + 'cos', + 'tan': + 'tan', + 'asin': + 'asin', + 'acos': + 'acos', + 'atan': + 'atan', + 'ln': + 'ln', + 'e^': + 'e^', + + // delimiters + 'whitespace': + 'tyhjien v\u00e4lien', + 'line': + 'rivinvaihtojen (lf)', + 'tab': + 'sarkaimien (tab)', + 'cr': + 'vaununpalautusten (cr)', + + // data types + 'number': + 'luku', + 'text': + 'teksti', + 'Boolean': + 'totuusarvo', + 'list': + 'lista', + 'command': + 'komentopalikka', + 'reporter': + 'funktiopalikka', + 'predicate': + 'predikaatti', + + // list indices + 'last': + 'viimeinen', + 'any': + 'mik\u00e4 tahansa' +}; @@ -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/lang-pt_BR.js b/lang-pt_BR.js new file mode 100755 index 0000000..f277c45 --- /dev/null +++ b/lang-pt_BR.js @@ -0,0 +1,1389 @@ +/*
+
+ lang-pt_BR.js
+
+ Brazilian Portuguese translation for SNAP!
+
+ translated by Aldo von Wangenheim
+
+ Copyright (C) 2014 by Aldo von Wangenheim
+
+ 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
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+ Note to Translators:
+ --------------------
+ At this stage of development, Snap! can be translated to any LTR language
+ maintaining the current order of inputs (formal parameters in blocks).
+
+ Translating Snap! is easy:
+
+
+ 1. Download
+
+ Download the sources and extract them into a local folder on your
+ computer:
+
+ <http://snap.berkeley.edu/snapsource/snap.zip>
+
+ Use the German translation file (named 'lang-de.js') as template for your
+ own translations. Start with editing the original file, because that way
+ you will be able to immediately check the results in your browsers while
+ you're working on your translation (keep the local copy of snap.html open
+ in your web browser, and refresh it as you progress with your
+ translation).
+
+
+ 2. Edit
+
+ Edit the translation file with a regular text editor, or with your
+ favorite JavaScript editor.
+
+ In the first non-commented line (the one right below this
+ note) replace "de" with the two-letter ISO 639-1 code for your language,
+ e.g.
+
+ fr - French => SnapTranslator.dict.fr = {
+ it - Italian => SnapTranslator.dict.it = {
+ pl - Polish => SnapTranslator.dict.pl = {
+ pt - Portuguese => SnapTranslator.dict.pt = {
+ es - Spanish => SnapTranslator.dict.es = {
+ el - Greek => => SnapTranslator.dict.el = {
+
+ etc. (see <http://en.wikipedia.org/wiki/ISO_639-1>)
+
+
+ 3. Translate
+
+ Then work through the dictionary, replacing the German strings against
+ your translations. The dictionary is a straight-forward JavaScript ad-hoc
+ object, for review purposes it should be formatted as follows:
+
+ {
+ 'English string':
+ 'Translation string',
+ 'last key':
+ } 'last value'
+
+ and you only edit the indented value strings. Note that each key-value
+ pair needs to be delimited by a comma, but that there shouldn't be a comma
+ after the last pair (again, just overwrite the template file and you'll be
+ fine).
+
+ If something doesn't work, or if you're unsure about the formalities you
+ should check your file with
+
+ <http://JSLint.com>
+
+ This will inform you about any missed commas etc.
+
+
+ 4. Accented characters
+
+ Depending on which text editor and which file encoding you use you can
+ directly enter special characters (e.g. Umlaut, accented characters) on
+ your keyboard. However, I've noticed that some browsers may not display
+ special characters correctly, even if other browsers do. So it's best to
+ check your results in several browsers. If you want to be on the safe
+ side, it's even better to escape these characters using Unicode.
+
+ see: <http://0xcc.net/jsescape/>
+
+
+ 5. Block specs:
+
+ At this time your translation of block specs will only work
+ correctly, if the order of formal parameters and their types
+ are unchanged. Placeholders for inputs (formal parameters) are
+ indicated by a preceding % prefix and followed by a type
+ abbreviation.
+
+ For example:
+
+ 'say %s for %n secs'
+
+ can currently not be changed into
+
+ 'say %n secs long %s'
+
+ and still work as intended.
+
+ Similarly
+
+ 'point towards %dst'
+
+ cannot be changed into
+
+ 'point towards %cst'
+
+ without breaking its functionality.
+
+
+ 6. Submit
+
+ When you're done, rename the edited file by replacing the "de" part of the
+ filename with the two-letter ISO 639-1 code for your language, e.g.
+
+ fr - French => lang-fr.js
+ it - Italian => lang-it.js
+ pl - Polish => lang-pl.js
+ pt - Portuguese => lang-pt.js
+ es - Spanish => lang-es.js
+ el - Greek => => lang-el.js
+
+ and send it to me for inclusion in the official Snap! distribution.
+ Once your translation has been included, Your name will the shown in the
+ "Translators" tab in the "About Snap!" dialog box, and you will be able to
+ directly launch a translated version of Snap! in your browser by appending
+
+ lang:xx
+
+ to the URL, xx representing your translations two-letter code.
+
+
+ 7. Known issues
+
+ In some browsers accents or ornaments located in typographic ascenders
+ above the cap height are currently (partially) cut-off.
+
+ Enjoy!
+ -Jens
+*/
+
+/*global SnapTranslator*/
+
+SnapTranslator.dict.pt_BR = {
+
+/*
+ Special characters: (see <http://0xcc.net/jsescape/>)
+
+ Ä, ä \u00c4, \u00e4
+ Ö, ö \u00d6, \u00f6
+ Ü, ü \u00dc, \u00fc
+ ß \u00df
+*/
+
+ // meta informação sobre a tradução
+ 'language_name':
+ 'Português do Brasil',
+ 'language_translator':
+ 'Aldo von Wangenheim',
+ 'translator_e-mail':
+ 'awangenh@inf.ufsc.br',
+ 'last_changed':
+ '2014-04-20',
+
+ // GUI
+ // control bar:
+ 'untitled':
+ 'Sem título',
+ 'development mode':
+ 'modo de desenvolvimento',
+
+ // categorias:
+ 'Motion':
+ 'Movimento',
+ 'Looks':
+ 'Aparência',
+ 'Sound':
+ 'Som',
+ 'Pen':
+ 'Caneta',
+ 'Control':
+ 'Controle',
+ 'Sensing':
+ 'Sensores',
+ 'Operators':
+ 'Operadores',
+ 'Variables':
+ 'Variáveis',
+ 'Lists':
+ 'Listas',
+ 'Other':
+ 'Outros',
+
+ // editor:
+ 'draggable':
+ 'arrastável',
+
+ // separadores:
+ 'Scripts':
+ 'Roteiros',
+ 'Costumes':
+ 'Fantasias',
+ 'Sounds':
+ 'Sons',
+
+ // nomes:
+ 'Sprite':
+ 'Ator',
+ 'Stage':
+ 'Palco',
+
+ // estilos de rotação:
+ 'don\'t rotate':
+ 'não rode',
+ 'can rotate':
+ 'rode',
+ 'only face left/right':
+ 'olhe apenas para a esquerda ou para a direita',
+
+ // botão de criação de novo actor:
+ 'add a new sprite':
+ 'adicionar um novo ator',
+
+ // ajuda nos tabuladores
+ 'costumes tab help':
+ 'Importa uma imagem de uma página Web ou de um\n'
+ + 'arquivo no teu computador arrastando-a para aqui',
+ 'import a sound from your computer\nby dragging it into here':
+ 'Importe um som de seu computador\narrastando-o para cá',
+
+ // blocos primitivos:
+
+ /*
+ Attention Translators:
+ ----------------------
+ At this time your translation of block specs will only work
+ correctly, if the order of formal parameters and their types
+ are unchanged. Placeholders for inputs (formal parameters) are
+ indicated by a preceding % prefix and followed by a type
+ abbreviation.
+
+ For example:
+
+ 'say %s for %n secs'
+
+ can currently not be changed into
+
+ 'say %n secs long %s'
+
+ and still work as intended.
+
+ Similarly
+
+ 'point towards %dst'
+
+ cannot be changed into
+
+ 'point towards %cst'
+
+ without breaking its functionality.
+ */
+
+ // Movimento:
+ 'Stage selected:\nno motion primitives':
+ 'Palco selecionado:\nsem primitivas de movimento',
+
+
+ 'move %n steps':
+ 'mova %n passos',
+ 'turn %clockwise %n degrees':
+ 'gire %clockwise %n graus',
+ 'turn %counterclockwise %n degrees':
+ 'gire %counterclockwise %n graus',
+ 'point in direction %dir':
+ 'aponte para a direção %dir graus',
+ 'point towards %dst':
+ 'aponte para %dst',
+ 'go to x: %n y: %n':
+ 'vá para x: %n , y: %n ',
+ 'go to %dst':
+ 'vá para %dst',
+ 'glide %n secs to x: %n y: %n':
+ 'deslize por %n segundos ate x: %n , y: %n ',
+ 'change x by %n':
+ 'adicione %n a x',
+ 'set x to %n':
+ 'mude x para %n',
+ 'change y by %n':
+ 'adicione %n a y',
+ 'set y to %n':
+ 'mude y para %n',
+ 'if on edge, bounce':
+ 'se tocar na borda, volte',
+ 'x position':
+ 'coordenada x da posição',
+ 'y position':
+ 'coordenada y da posição',
+ 'direction':
+ 'direção',
+
+ // Aparência:
+ 'switch to costume %cst':
+ 'mude para a fantasia %cst',
+ 'next costume':
+ 'próxima fantasia',
+ 'costume #':
+ 'n° da fantasia',
+ 'say %s for %n secs':
+ 'diga %s por %n segundos',
+ 'say %s':
+ 'diga %s',
+ 'think %s for %n secs':
+ 'pense %s por %n segundos',
+ 'think %s':
+ 'pense %s',
+ 'Hello!':
+ 'Olá!',
+ 'Hmm...':
+ 'Hmm…',
+ 'change %eff effect by %n':
+ 'adicione ao efeito %eff %n',
+ 'set %eff effect to %n':
+ 'mude o efeito %eff para %n',
+ 'clear graphic effects':
+ 'apague os efeitos gráficos',
+ 'change size by %n':
+ 'adicione %n ao seu tamanho',
+ 'set size to %n %':
+ 'mude o tamanho para %n %',
+ 'size':
+ 'tamanho',
+ 'show':
+ 'mostrar',
+ 'hide':
+ 'esconder',
+ 'go to front':
+ 'vá para a frente',
+ 'go back %n layers':
+ 'vá %n camadas para trás',
+
+ 'development mode \ndebugging primitives:':
+ 'primitivas de depuração \ndo modo de desenvolvimento:',
+ 'console log %mult%s':
+ 'registre %mult%s no console',
+ 'alert %mult%s':
+ 'mostre janela de alerta com %mult%s',
+
+ // Som:
+ 'play sound %snd':
+ 'toque o som %snd',
+ 'play sound %snd until done':
+ 'toque o som %snd até o fim',
+ 'stop all sounds':
+ 'pare todos os sons',
+ 'rest for %n beats':
+ 'silêncio por %n tempos',
+ 'play note %n for %n beats':
+ 'toque a nota %n durante %n tempos',
+ 'change tempo by %n':
+ 'adicione %n tempos ao andamento',
+ 'set tempo to %n bpm':
+ 'altere o andamento para %n tempos',
+ 'tempo':
+ 'andamento',
+
+ // Caneta:
+ 'clear':
+ 'apague tudo',
+ 'pen down':
+ 'use a caneta',
+ 'pen up':
+ 'levante a caneta',
+ 'set pen color to %clr':
+ 'mude a cor da caneta para %clr',
+ 'change pen color by %n':
+ 'adicione %n à cor da caneta',
+ 'set pen color to %n':
+ 'mude a cor da caneta para %n',
+ 'change pen shade by %n':
+ 'adicione %n à intensidade da caneta',
+ 'set pen shade to %n':
+ 'mude a intensidade da caneta para %n',
+ 'change pen size by %n':
+ 'adicione %n à espessura da caneta',
+ 'set pen size to %n':
+ 'mude a espessura da caneta para %n',
+ 'stamp':
+ 'carimbe',
+
+ // Eventos e Controle:
+ 'when %greenflag clicked':
+ 'quando clicar em %greenflag',
+ 'when %keyHat key pressed':
+ 'quando a tecla %keyHat for pressionada',
+ 'when I am clicked':
+ 'quando este ator for clicado',
+ 'when I receive %msgHat':
+ 'quando receber %msgHat',
+ 'broadcast %msg':
+ 'envie %msg a todos',
+ 'broadcast %msg and wait':
+ 'envie %msg a todos e espere',
+ 'Message name':
+ 'nome da mensagem',
+ 'message':
+ 'mensagem',
+ 'any message':
+ 'qualquer mensagem',
+ 'wait %n secs':
+ 'espere %n segundos',
+ 'wait until %b':
+ 'espere até que %b',
+ 'forever %c':
+ 'sempre %c',
+ 'repeat %n %c':
+ 'repita %n vezes %c',
+ 'repeat until %b %c':
+ 'repita até que %b %c',
+ 'if %b %c':
+ 'se %b então %c',
+ 'if %b %c else %c':
+ 'se %b então %c senão %c',
+ 'report %s':
+ 'reporte %s',
+ 'stop %stopChoices':
+ 'pare %stopChoices',
+ 'all':
+ 'tudo',
+ 'this script':
+ 'este roteiro',
+ 'this block':
+ 'este bloco',
+ 'stop %stopOthersChoices':
+ 'pare %stopOthersChoices',
+ 'all but this script':
+ 'todos os roteiros exceto este',
+ 'other scripts in sprite':
+ 'outros roteiros deste ator',
+ 'pause all %pause':
+ 'pause tudo %pause',
+ 'run %cmdRing %inputs':
+ 'execute %cmdRing %inputs',
+ 'launch %cmdRing %inputs':
+ 'inicie execução de %cmdRing %inputs',
+ 'call %repRing %inputs':
+ 'chame %repRing %inputs',
+ 'run %cmdRing w/continuation':
+ 'execute %cmdRing com continuação',
+ 'call %cmdRing w/continuation':
+ 'chame %cmdRing com continuação',
+ 'warp %c':
+ 'execute atomicamente %c',
+ 'when I start as a clone':
+ 'quando este ator começar como clone',
+ 'create a clone of %cln':
+ 'crie clone de %cln',
+ 'myself':
+ 'este ator',
+ 'delete this clone':
+ 'apague este clone',
+
+ // Sensores:
+ 'touching %col ?':
+ 'tocando em %col',
+ 'touching %clr ?':
+ 'tocando na cor %clr',
+ 'color %clr is touching %clr ?':
+ 'a cor %clr está tocando na cor %clr',
+ 'ask %s and wait':
+ 'pergunte %s e espere a resposta',
+ 'what\'s your name?':
+ 'qual o seu nome?',
+ 'answer':
+ 'resposta',
+ 'mouse x':
+ 'posição x do mouse',
+ 'mouse y':
+ 'posição y do mouse',
+ 'mouse down?':
+ 'mouse pressionado?',
+ 'key %key pressed?':
+ 'tecla %key pressionada?',
+ 'distance to %dst':
+ 'distância até %dst',
+ 'reset timer':
+ 'zere o cronómetro',
+ 'timer':
+ 'valor do cronómetro',
+ '%att of %spr':
+ '%att de %spr',
+ 'http:// %s':
+ 'página http:// %s',
+ 'turbo mode?':
+ 'modo turbo?',
+ 'set turbo mode to %b':
+ 'mude o modo turbo para %b',
+
+ 'filtered for %clr':
+ 'filtrado por %clr',
+ 'stack size':
+ 'altura da pilha',
+ 'frames':
+ 'quadros',
+
+ // Operadores:
+ '%n mod %n':
+ 'resto de %n por %n',
+ 'round %n':
+ 'arredondamento de %n',
+ '%fun of %n':
+ '%fun de %n',
+ 'pick random %n to %n':
+ 'escolha um valor ao acaso entre %n e %n',
+ '%b and %b':
+ '%b e %b',
+ '%b or %b':
+ '%b ou %b',
+ 'not %b':
+ 'não %b',
+ 'true':
+ 'verdadeiro',
+ 'false':
+ 'falso',
+ 'join %words':
+ 'junte %words',
+ 'split %s by %delim':
+ 'separe %s por %delim',
+ 'hello':
+ 'Olá',
+ 'world':
+ 'mundo',
+ 'letter %n of %s':
+ 'o caractere %n de %s',
+ 'length of %s':
+ 'o comprimento de %s',
+ 'unicode of %s':
+ 'o código Unicode do caractere %s',
+ 'unicode %n as letter':
+ 'o caractere cujo código Unicode é %n',
+ 'is %s a %typ ?':
+ '%s é um/uma %typ',
+ 'is %s identical to %s ?':
+ '%s é idêntico a %s',
+
+ 'type of %s':
+ 'o tipo de %s',
+
+ // Variáveis:
+ 'Make a variable':
+ 'Criar uma variável',
+ 'Variable name':
+ 'Nome da variável',
+ 'Script variable name':
+ 'Nome da variável de Roteiro',
+ 'Delete a variable':
+ 'Remova uma variável',
+
+ 'set %var to %s':
+ 'mude %var para %s',
+ 'change %var by %n':
+ 'adicione a %var o valor %n',
+ 'show variable %var':
+ 'mostre variável %var',
+ 'hide variable %var':
+ 'esconda variável %var',
+ 'script variables %scriptVars':
+ 'crie as variáveis de roteiro %scriptVars',
+
+ // listas:
+ 'list %exp':
+ 'uma lista com %exp',
+ '%s in front of %l':
+ '%s inicia %l',
+ 'item %idx of %l':
+ '%idx de %l',
+ 'all but first of %l':
+ 'todos elementos de %l menos o primeiro',
+ 'length of %l':
+ 'tamanho de %l',
+ '%l contains %s':
+ '%l contém %s',
+ 'thing':
+ 'valor',
+ 'add %s to %l':
+ 'adicione %s a %l',
+ 'delete %ida of %l':
+ 'apague %ida de %l',
+ 'insert %s at %idx of %l':
+ 'insira %s na posição %idx em %l',
+ 'replace item %idx of %l with %s':
+ 'substitua o item %idx de %l por %s',
+
+ // Outros
+ 'Make a block':
+ 'Criar um bloco',
+
+ // Menus
+ // Snap menu
+ 'About...':
+ 'Sobre Snap!…',
+ 'Reference manual':
+ 'Manual de Referência',
+ 'Snap! website':
+ 'Site do Snap!',
+ 'Download source':
+ 'Baixar código fonte',
+ 'Switch back to user mode':
+ 'Volte ao modo de usuário',
+ 'disable deep-Morphic\ncontext menus\nand show user-friendly ones':
+ 'Desative menus de contexto\nprofundos do Morphic e\nmostrar menus amigáveis.',
+ 'Switch to dev mode':
+ 'Mude para modo de desenvolvimento',
+ 'enable Morphic\ncontext menus\nand inspectors,\nnot user-friendly!':
+ 'Ativar menus de contexto\ne inspectores não\namigáveis do Morphic!',
+
+ // Menu de projeto
+ 'Project notes...':
+ 'Notas deste projeto…',
+ 'New':
+ 'Criar um novo projeto',
+ 'Open...':
+ 'Abrir um projeto…',
+ 'Save':
+ 'Salvar',
+ 'Save As...':
+ 'Salvar como…',
+ 'Import...':
+ 'Importar…',
+ 'file menu import hint':
+ 'Importar para este projecto\num projeto exportado,\n'
+ + 'uma biblioteca de blocos,\n'
+ + 'um traje ou um som.',
+ 'Export project as plain text...':
+ 'Exportar este projeto em modo texto…',
+ 'Export project...':
+ 'Exportar este projeto…',
+ 'show project data as XML\nin a new browser window':
+ 'Mostrar os dados no\nformato XML numa nova janela do navegador.',
+ 'Export blocks...':
+ 'Exportar blocos…',
+ 'show global custom block definitions as XML\nin a new browser window':
+ 'Mostrar as definições globais de blocos\npersonalizados no formato\nXML numa nova janela do navegador.',
+ 'Import tools':
+ 'Importar ferramentas oficiais',
+ 'load the official library of\npowerful blocks':
+ 'Importar a biblioteca\n oficial de blocos.',
+ 'Libraries...':
+ 'Bibliotecas...',
+ 'Import library':
+ 'Importar biblioteca',
+
+ // Menu da nuvem
+ 'Login...':
+ 'Entrar na sua conta…',
+ 'Signup...':
+ 'Registar uma nova conta…',
+
+ // menu de preferências
+ 'Language...':
+ 'Língua…',
+ 'Zoom blocks...':
+ 'Zoom dos blocos…',
+ 'Blurred shadows':
+ 'Sombras borradas',
+ 'uncheck to use solid drop\nshadows and highlights':
+ 'Desmarque para usar sombras\ne realces nítidos.',
+ 'check to use blurred drop\nshadows and highlights':
+ 'Marque para usar sombras\ne realces borrados.',
+ 'Zebra coloring':
+ 'Coloração em zebra',
+ 'check to enable alternating\ncolors for nested blocks':
+ 'Marque para alternar\nas cores de blocos aninhados.',
+ 'uncheck to disable alternating\ncolors for nested block':
+ 'Desmarque para deixar de alternar\nas cores de blocos aninhados.',
+ 'Dynamic input labels':
+ 'Nomes de entrada dinâmicos',
+ 'uncheck to disable dynamic\nlabels for variadic inputs':
+ 'Desmarque para desativar nomes\ndinâmicos nas variáveis de entrada.',
+ 'check to enable dynamic\nlabels for variadic inputs':
+ 'Marque para ativar nomes\ndinâmicos nas variáveis de entrada.',
+ 'Prefer empty slot drops':
+ 'Procure encaixar blocos de valor (repórteres) em campos vazios ao soltar',
+ 'settings menu prefer empty slots hint':
+ 'Marque para focar em campos vazios\nquando estiver arrastando e '
+ + 'soltando blocos de valor (repórteres).',
+ 'uncheck to allow dropped\nreporters to kick out others':
+ 'Desmarque para permitir que blocos\nrepórteres soltos em um campo '
+ + 'desalojem outros.',
+ 'Long form input dialog':
+ 'Forma longa da caixa de diálogo dos parâmetros',
+ 'Plain prototype labels':
+ 'Use texto simples para protótipos',
+ 'uncheck to always show (+) symbols\nin block prototype labels':
+ 'Desmarque para mostrar sempre os símbolos (+)\nno texto dos protótipos dos blocos',
+ 'check to hide (+) symbols\nin block prototype labels':
+ 'Marque para esconder os símbolos (+)\nno texto dos protótipos dos blocos',
+ 'check to always show slot\ntypes in the input dialog':
+ 'Marque para sempre mostrar\no tipo dos campos na caixa\nde diálogo dos parâmetros.',
+ 'uncheck to use the input\ndialog in short form':
+ 'Desmarque para usar texto abreviado\nda caixa de diálogo dos parâmetros.',
+ 'Virtual keyboard':
+ 'Teclado virtual',
+ 'uncheck to disable\nvirtual keyboard support\nfor mobile devices':
+ 'Desmarque para desativar o\nsuporte ao teclado virtual\npara dispositivos '
+ + 'móveis.',
+ 'check to enable\nvirtual keyboard support\nfor mobile devices':
+ 'Marque para ativar o\nsuporte ao teclado virtual\npara dispositivos '
+ + 'móveis.',
+ 'Input sliders':
+ 'Sliders nos campos de entrada',
+ 'uncheck to disable\ninput sliders for\nentry fields':
+ 'Desmarque para desativar\nsliders nos campos de entrada dos blocos.',
+ 'check to enable\ninput sliders for\nentry fields':
+ 'Marque para ativar\nsliders nos campos de entrada dos blocos.',
+ 'Clicking sound':
+ 'Som de cliques',
+ 'uncheck to turn\nblock clicking\nsound off':
+ 'Desmarque para desativar o som\nproduzido ao clicar nos blocos.',
+ 'check to turn\nblock clicking\nsound on':
+ 'Marque para ativar o som\nproduzido ao clicar nos blocos.',
+ 'Animations':
+ 'Animações',
+ 'uncheck to disable\nIDE animations':
+ 'Desmarque para desativar\nas animações da interface de usuário.',
+ 'Turbo mode.':
+ 'Modo turbo',
+ 'check to prioritize\nscript execution':
+ 'Marque para priorizar\na execução de roteiros.',
+ 'uncheck to run scripts\nat normal speed':
+ 'Desmarque para executar os roteiros\nna velocidade normal.',
+ 'check to enable\nIDE animations':
+ 'Marque para ativar\nas animações da interface de usuário.',
+ 'Thread safe scripts':
+ 'Roteiros seguros face a threads',
+ 'uncheck to allow\nscript reentrance':
+ 'Desmarque para permitir\nreentrância nos roteiros.',
+ 'check to disallow\nscript reentrance':
+ 'Marque para não permitir\nreentrância nos roteiros.',
+ 'Prefer smooth animations':
+ 'Prefira animações suaves',
+ 'uncheck for greater speed\nat variable frame rates':
+ 'Desmarque para aumentar a velocidade\npermitindo ritmos variáveis das tramas nas animações.',
+ 'check for smooth, predictable\nanimations across computers':
+ 'Marque para obter animações mais suaves\ne previsíveis de computador para computador.',
+
+ // Entradas
+ 'with inputs':
+ 'com argumentos',
+ 'input names:':
+ 'com parâmetros',
+ 'Input Names:':
+ 'Parâmetros:',
+ 'input list:':
+ 'lista de entradas',
+
+ // menus de contexto:
+ 'help':
+ 'ajuda',
+
+ // palette:
+ 'hide primitives':
+ 'esconda blocos primitivos',
+ 'show primitives':
+ 'mostre blocos primitivos',
+
+ // blocos:
+ 'help...':
+ 'ajuda…',
+ 'relabel...':
+ 'renomear…',
+ 'duplicate':
+ 'duplicar',
+ 'make a copy\nand pick it up':
+ 'Faça uma cópia do\nbloco e pegue-a.',
+ 'only duplicate this block':
+ 'Duplique apenas este bloco.',
+ 'delete':
+ 'apague',
+ 'script pic...':
+ 'fotografia do roteiro',
+ 'open a new window\nwith a picture of this script':
+ 'Abra uma nova janela com\numa fotografia deste roteiro.',
+ 'ringify':
+ 'adicione anel',
+ 'unringify':
+ 'apague anel',
+
+ // blocos personalizados:
+ 'delete block definition...':
+ 'remova definição do bloco…',
+ 'edit...':
+ 'editar…',
+
+ // Atores:
+ 'edit':
+ 'editar',
+ 'detach from':
+ 'desencaixe de',
+ 'detach all parts':
+ 'desencaixe todas as partes',
+ 'export...':
+ 'exportar…',
+
+ // palco:
+ 'show all':
+ 'mostre todos os atores',
+ 'pic...':
+ 'fotografia…',
+ 'open a new window\nwith a picture of the stage':
+ 'Abrir uma nova janela com\numa fotografia do palco.',
+
+ // área de Roteiros:
+ 'clean up':
+ 'limpar',
+ 'arrange scripts\nvertically':
+ 'Organize roteiros\nverticalmente.',
+ 'add comment':
+ 'adicione um comentário',
+ 'undrop':
+ 'desfaça posicionamento',
+ 'undo the last\nblock drop\nin this pane':
+ 'Desfazer o último posicionamento de um bloco\nneste painel.',
+ 'scripts pic...':
+ 'fotografe os roteiros…',
+ 'open a new window\nwith a picture of all scripts':
+ 'Abra uma nova janela com\numa fotografia de todos os roteiros.',
+ 'make a block...':
+ 'crie um bloco…',
+
+ // Fantasias:
+ 'rename':
+ 'renomear',
+ 'export':
+ 'exportar',
+ 'rename costume':
+ 'Qual o novo nome da fantasia?',
+
+ // Sons
+ 'Play sound':
+ 'Toque som.',
+ 'Stop sound':
+ 'Pare som.',
+ 'Stop':
+ 'Parar',
+ 'Play':
+ 'Tocar',
+ 'rename sound':
+ 'Qual o novo nome do som?',
+
+ // Caixas de diálogo
+ // botões
+ 'OK':
+ 'OK',
+ 'Ok':
+ 'OK',
+ 'Cancel':
+ 'Cancela',
+ 'Yes':
+ 'Sim',
+ 'No':
+ 'Não',
+
+ // ajuda
+ 'Help':
+ 'Ajuda',
+
+ // ampliação de blocos
+ 'Zoom blocks':
+ 'Zoom dos blocos',
+ 'build':
+ 'construa',
+ 'your own':
+ 'os seus próprios',
+ 'blocks':
+ 'blocos',
+ 'normal (1x)':
+ 'normal (1x)',
+ 'demo (1.2x)':
+ 'demonstração (1.2x)',
+ 'presentation (1.4x)':
+ 'apresentação (1.4x)',
+ 'big (2x)':
+ 'grande (2x)',
+ 'huge (4x)':
+ 'enorme (4x)',
+ 'giant (8x)':
+ 'gigante (8x)',
+ 'monstrous (10x)':
+ 'monstruoso (10x)',
+
+ // Gestor de Projetos
+ 'Untitled':
+ 'Sem título',
+ 'Open Project':
+ 'Abrir Projeto',
+ '(empty)':
+ '(vazio)',
+ 'Saved!':
+ 'Salvo!',
+ 'Delete Project':
+ 'Apague Projeto',
+ 'Are you sure you want to delete':
+ 'Tem certeza que deseja apagar?',
+ 'rename...':
+ 'alterar o nome…',
+
+ // Editor de fantasias
+ 'Costume Editor':
+ 'Editor de Fantasias',
+ 'click or drag crosshairs to move the rotation center':
+ 'Clique ou arraste a mira para mudar o centro de rotação.',
+
+ // Anotaes de projeto
+ 'Project Notes':
+ 'Notas do Projeto',
+
+ // Novo projeto
+ 'New Project':
+ 'Novo Projeto',
+ 'Replace the current project with a new one?':
+ 'Substituir este projeto por um novo projeto?',
+
+ // guardar projecto
+ 'Save Project As...':
+ 'Salvar Projeto Como…',
+
+ // exportar blocos
+ 'Export blocks':
+ 'Exportar blocos',
+ 'Import blocks':
+ 'Importar blocos',
+ 'this project doesn\'t have any\ncustom global blocks yet':
+ 'Este projeto ainda não possui\nnenhum bloco global personalizado.',
+ 'select':
+ 'selecionar',
+ 'none':
+ 'nenhum',
+
+ // Caixa de diálogo de variáveis
+ 'for all sprites':
+ 'para todos os atores',
+ 'for this sprite only':
+ 'apenas para este ator',
+
+ // caixa de diálogo de blocos
+ 'Change block':
+ 'Altere o tipo do bloco',
+ 'Command':
+ 'Comando',
+ 'Reporter':
+ 'Repórter',
+ 'Predicate':
+ 'Predicado',
+
+ // editor de blocos
+ 'Block Editor':
+ 'Editor de Blocos',
+ 'Apply':
+ 'Aplicar',
+
+ // caixa de diálogo de remoção de bloco
+ 'Delete Custom Block':
+ 'Remova Bloco Personalizado',
+ 'block deletion dialog text':
+ 'Quer mesmo remover este bloco e '
+ + 'todas as suas aplicações?',
+
+ // Caixa de diálogo de parâmetros
+ 'Create input name':
+ 'Criar parâmetro',
+ 'Edit input name':
+ 'Editar parâmetro',
+ 'Edit label fragment':
+ 'Editar rótulo',
+ 'Title text':
+ 'Nome',
+ 'Input name':
+ 'Parâmetro',
+ 'Delete':
+ 'Remover',
+ 'Object':
+ 'Objeto',
+ 'Number':
+ 'Número',
+ 'Text':
+ 'Texto',
+ 'List':
+ 'Lista',
+ 'Any type':
+ 'Qualquer tipo',
+ 'Boolean (T/F)':
+ 'Booleano (V/F)',
+ 'Command\n(inline)':
+ 'Comando\n(em linha)',
+ 'Command\n(C-shape)':
+ 'Comando\n(bloco de repetição)',
+ 'Any\n(unevaluated)':
+ 'Repórter\n(forma especial)',
+ 'Boolean\n(unevaluated)':
+ 'Predicado\n(forma especial)',
+ 'Single input.':
+ 'Parâmetro único.',
+ 'Default Value:':
+ 'Valor em caso de omissão:',
+ 'Multiple inputs (value is list of inputs)':
+ 'Múltiplos argumentos (o valor do parâmetro é a lista dos argumentos).',
+ 'Upvar - make internal variable visible to caller':
+ 'Tornar o parâmetro visível ao invocador.',
+
+ // Acerca do Snap
+ 'About Snap':
+ 'Sobre o Snap!',
+ 'Back...':
+ 'Para trás…',
+ 'License...':
+ 'Licença…',
+ 'Modules...':
+ 'Módulos…',
+ 'Credits...':
+ 'Créditos…',
+ 'Translators...':
+ 'Tradutores…',
+ 'License':
+ 'Licença',
+ 'current module versions:':
+ 'versões actuais dos módulos',
+ 'Contributors':
+ 'Contribuidores',
+ 'Translations':
+ 'Traduções',
+
+ // observadores de variáveis
+ 'normal':
+ 'normal',
+ 'large':
+ 'grande',
+ 'slider':
+ 'slider',
+ 'slider min...':
+ 'mínimo do slider…',
+ 'slider max...':
+ 'máximo do slider…',
+ 'import...':
+ 'importar…',
+ 'Slider minimum value':
+ 'Valor mínimo do potenciómetro deslizante',
+ 'Slider maximum value':
+ 'Valor máximo do potenciómetro deslizante',
+
+ // observadores de listas
+ 'length: ':
+ 'tamanho: ',
+
+ // comentários
+ 'add comment here...':
+ 'coloque aqui um comentário…',
+
+ // drop downs
+ // direcções
+ '(90) right':
+ '90° (direita)',
+ '(-90) left':
+ '-90° (esquerda)',
+ '(0) up':
+ '0° (acima)',
+ '(180) down':
+ '180° (abaixo)',
+
+ // detecção de colisões
+ 'mouse-pointer':
+ 'ponteiro do mouse',
+ 'edge':
+ 'borda',
+ 'pen trails':
+ 'traços da caneta',
+
+ // trajes
+ 'Turtle':
+ 'seta',
+ 'Empty':
+ 'vazio',
+
+ // efeitos gráficos
+ 'ghost':
+ 'fantasma',
+
+ // teclas
+ 'space':
+ 'espaço',
+ 'up arrow':
+ 'seta para cima',
+ 'down arrow':
+ 'seta para baixo',
+ 'right arrow':
+ 'seta para a direita',
+ 'left arrow':
+ 'seta para a esquerda',
+ 'a':
+ 'a',
+ 'b':
+ 'b',
+ 'c':
+ 'c',
+ 'd':
+ 'd',
+ 'e':
+ 'e',
+ 'f':
+ 'f',
+ 'g':
+ 'g',
+ 'h':
+ 'h',
+ 'i':
+ 'i',
+ 'j':
+ 'j',
+ 'k':
+ 'k',
+ 'l':
+ 'l',
+ 'm':
+ 'm',
+ 'n':
+ 'n',
+ 'o':
+ 'o',
+ 'p':
+ 'p',
+ 'q':
+ 'q',
+ 'r':
+ 'r',
+ 's':
+ 's',
+ 't':
+ 't',
+ 'u':
+ 'u',
+ 'v':
+ 'v',
+ 'w':
+ 'w',
+ 'x':
+ 'x',
+ 'y':
+ 'y',
+ 'z':
+ 'z',
+ '0':
+ '0',
+ '1':
+ '1',
+ '2':
+ '2',
+ '3':
+ '3',
+ '4':
+ '4',
+ '5':
+ '5',
+ '6':
+ '6',
+ '7':
+ '7',
+ '8':
+ '8',
+ '9':
+ '9',
+
+ // messagens
+ 'new...':
+ 'Nova…',
+
+ // funções matemáticas
+ 'abs':
+ 'valor absoluto',
+ 'floor':
+ 'arredondamento para baixo',
+ 'sqrt':
+ 'raiz quadrada',
+ 'sin':
+ 'seno',
+ 'cos':
+ 'cosseno',
+ 'tan':
+ 'tangente',
+ 'asin':
+ 'arco-seno',
+ 'acos':
+ 'arco-cosseno',
+ 'atan':
+ 'arco-tangente',
+ 'ln':
+ 'logaritmo natural',
+ 'e^':
+ 'exponencial',
+
+ // delimitadores
+ 'whitespace':
+ 'espaços em branco',
+ 'line':
+ 'avanços de linha',
+ 'tab':
+ 'tabuladores',
+ 'cr':
+ 'retornos',
+
+ // tipos de dados
+ 'number':
+ 'número',
+ 'text':
+ 'texto',
+ 'Boolean':
+ 'booleano',
+ 'list':
+ 'lista',
+ 'command':
+ 'comando',
+ 'reporter':
+ 'repórter',
+ 'predicate':
+ 'predicado',
+
+ // índices de listas
+ 'last':
+ 'último item',
+ 'any':
+ 'um item ao acaso',
+
+ // em falta no ficheiro lang-de.js
+ 'costume name':
+ 'nome da fantasia',
+ 'Open':
+ 'Abrir',
+ 'Share':
+ 'Compartilhar',
+ 'Cloud':
+ 'Nuvem',
+ 'Browser':
+ 'Navegador',
+ 'Sign up':
+ 'Registrar nova conta',
+ 'Sign in':
+ 'Entrar',
+ 'now connected.':
+ 'entrou.',
+ 'disconnected.':
+ 'saiu.',
+ 'Reset password':
+ 'Recuperar senha',
+ 'Reset Password...':
+ 'Recuperar a sua senha...',
+ 'User name:':
+ 'Nome de usuário:',
+ 'Password:':
+ 'Senha:',
+ 'Birth date:':
+ 'Data de nascimento:',
+ 'January':
+ 'Janeiro',
+ 'February':
+ 'Fevereiro',
+ 'March':
+ 'Março',
+ 'April':
+ 'Abril',
+ 'May':
+ 'Maio',
+ 'June':
+ 'Junho',
+ 'July':
+ 'Julho',
+ 'August':
+ 'Agosto',
+ 'September':
+ 'Setembro',
+ 'October':
+ 'Outubro',
+ 'November':
+ 'Novembro',
+ 'December':
+ 'Dezembro',
+ 'year:':
+ 'ano:',
+ ' or before':
+ ' ou antes',
+ 'E-mail address:':
+ 'Endereço de email:',
+ 'E-mail address of parent or guardian:':
+ 'Endereço de encarregado de educação:',
+ 'Terms of Service...':
+ 'Termos do Serviço…',
+ 'Privacy...':
+ 'Privacidade…',
+ 'I have read and agree\nto the Terms of Service':
+ 'Li e declaro concordar\ncom os Termos do Serviço',
+ 'stay signed in on this computer\nuntil logging out':
+ 'manter-me autenticado neste\ncomputador até que saia',
+ 'please fill out\nthis field':
+ 'Por favor preencha\neste campo.',
+ 'User name must be four\ncharacters or longer':
+ 'O nome de usuário tem de ter\npelo menos quatro caracteres.',
+ 'please provide a valid\nemail address':
+ 'Por favor indique um endereço\nde email válido.',
+ 'password must be six\ncharacters or longer':
+ 'A senha tem de ter\npelo menos seis caracteres.',
+ 'passwords do\nnot match':
+ 'As senhas\nnão correspondem.',
+ 'please agree to\nthe TOS':
+ 'Por favor concorde com\nos Termos do Serviço.',
+ 'Examples':
+ 'Exemplos',
+ 'You are not logged in':
+ 'Ainda não se autenticou',
+ 'Updating\nproject list...':
+ 'Atualizando a\nlista de projetos…',
+ 'Opening project...':
+ 'Abrindo o projeto…',
+ 'Fetching project from the cloud...':
+ 'Obtendo o projeto da nuvem…',
+ 'Saving project to the cloud...':
+ 'Salvando o projeto na nuvem…',
+ 'Sprite Nesting':
+ 'Atores aninhados',
+ 'uncheck to disable\nsprite composition':
+ 'Desmarque para desativar\na composição de atores.',
+ 'Codification support':
+ 'Suportar produção de código',
+ 'check for block\nto text mapping features':
+ 'Assinalar para funcionalidades\nde mapeamento entre blocos e texto.',
+ 'Save to disk':
+ 'Salvar no disco',
+ 'experimental - store this project\nin your downloads folder':
+ 'Experimental - Salvar este projeto\nna sua pasta de downloads.',
+ 'saved.':
+ 'salvo.',
+ 'options...':
+ 'opções…',
+ 'read-only':
+ 'apenas leitura',
+ 'Input Slot Options':
+ 'Opções de Campos de Entrada',
+ 'Enter one option per line.Optionally use "=" as key/value delimiter\ne.g.\n the answer=42':
+ 'Entre com uma opção por linha. Opcionalmente, use "=" como separador\nentre chave e valor, e.g.\n a resposta=42',
+ 'paint a new sprite':
+ 'Desenhar um novo ator.',
+ 'Paint a new costume':
+ 'Desenhar uma nova fantasia.',
+ 'add a new Turtle sprite':
+ 'Adicionar um novo ator.',
+ 'Flat design':
+ 'Visual plano',
+ 'check for alternative\nGUI design':
+ 'Marque para um design alternativo\nda interface gráfica de usuário.',
+ 'Rasterize SVGs':
+ 'Transformar desenhos vetorias (SVG) em mapas de bits',
+ 'check to rasterize\nSVGs on import':
+ 'Marque para transformar os arquivos vetoriais SVG\nem mapas de bits durante a importação.',
+ 'comment pic...':
+ 'fotografia do comentário…',
+ 'open a new window\nwith a picture of this comment':
+ 'Abrir uma nova janela com\numa fotografia deste comentário.'
+};
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-April-30'; // Global stuff @@ -149,7 +149,7 @@ SnapTranslator.dict.de = { 'translator_e-mail': 'jens@moenig.org', 'last_changed': - '2013-10-04' + '2014-02-13' }; 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 = { @@ -368,4 +368,29 @@ SnapTranslator.dict.ca = { 'tibabenfortlapalanca@gmail.com', 'last_changed': '2013-11-26' -};
\ No newline at end of file +}; + +SnapTranslator.dict.fi = { + // meta information + 'language_name': + 'suomi', + 'language_translator': + 'Jouni K. Sepp\u00e4nen', + 'translator_e-mail': + 'jks@iki.fi', + 'last_changed': + '2014-04-18' +}; + +SnapTranslator.dict.pt_BR = { + // meta information + 'language_name': + 'Português do Brasil', + 'language_translator': + 'Aldo von Wangenheim', + 'translator_e-mail': + 'awangenh@inf.ufsc.br', + 'last_changed': + '2014-04-20' +}; + @@ -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-19'; +modules.objects = '2014-March-31'; 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; @@ -388,6 +389,12 @@ SpriteMorph.prototype.initBlocks = function () { }, // Looks - Debugging primitives for development mode + reportCostumes: { + type: 'reporter', + category: 'looks', + spec: 'wardrobe' + }, + alert: { type: 'command', category: 'looks', @@ -445,6 +452,13 @@ SpriteMorph.prototype.initBlocks = function () { spec: 'tempo' }, + // Sound - Debugging primitives for development mode + reportSounds: { + type: 'reporter', + category: 'sound', + spec: 'jukebox' + }, + // Pen clear: { type: 'command', @@ -581,6 +595,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 +608,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 +659,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', @@ -786,6 +817,11 @@ SpriteMorph.prototype.initBlocks = function () { category: 'sensing', spec: 'set turbo mode to %b' }, + reportDate: { + type: 'reporter', + category: 'sensing', + spec: 'current %dates' + }, // Operators reifyScript: { @@ -1079,6 +1115,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'], @@ -1125,9 +1180,6 @@ SpriteMorph.prototype.blockAlternatives = { receiveClick: ['receiveGo'], doBroadcast: ['doBroadcastAndWait'], doBroadcastAndWait: ['doBroadcast'], - doStopBlock: ['doStop', 'doStopAll'], - doStop: ['doStopBlock', 'doStopAll'], - doStopAll: ['doStopBlock', 'doStop'], // sensing: getLastAnswer: ['getTimer'], @@ -1407,8 +1459,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() @@ -1421,8 +1474,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) { @@ -1580,6 +1633,8 @@ SpriteMorph.prototype.blockTemplates = function (category) { txt.setColor(this.paletteTextColor); blocks.push(txt); blocks.push('-'); + blocks.push(block('reportCostumes')); + blocks.push('-'); blocks.push(block('log')); blocks.push(block('alert')); } @@ -1601,6 +1656,20 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(watcherToggle('getTempo')); blocks.push(block('getTempo')); + // for debugging: /////////////// + + if (this.world().isDevMode) { + blocks.push('-'); + txt = new TextMorph(localize( + 'development mode \ndebugging primitives:' + )); + txt.fontSize = 9; + txt.setColor(this.paletteTextColor); + blocks.push(txt); + blocks.push('-'); + blocks.push(block('reportSounds')); + } + } else if (cat === 'pen') { blocks.push(block('clear')); @@ -1646,9 +1715,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')); @@ -1700,6 +1774,8 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push('-'); blocks.push(block('reportIsFastTracking')); blocks.push(block('doSetFastTracking')); + blocks.push('-'); + blocks.push(block('reportDate')); // for debugging: /////////////// @@ -2215,6 +2291,11 @@ SpriteMorph.prototype.doWearPreviousCostume = function () { }; SpriteMorph.prototype.doSwitchToCostume = function (id) { + if (id instanceof Costume) { // allow first-class costumes + this.wearCostume(id); + return; + } + var num, arr = this.costumes.asArray(), costume; @@ -2245,6 +2326,10 @@ SpriteMorph.prototype.doSwitchToCostume = function (id) { this.wearCostume(costume); }; +SpriteMorph.prototype.reportCostumes = function () { + return this.costumes; +}; + // SpriteMorph sound management SpriteMorph.prototype.addSound = function (audio, name) { @@ -2270,6 +2355,10 @@ SpriteMorph.prototype.playSound = function (name) { } }; +SpriteMorph.prototype.reportSounds = function () { + return this.sounds; +}; + // SpriteMorph user menu SpriteMorph.prototype.userMenu = function () { @@ -2678,8 +2767,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); @@ -4301,6 +4395,8 @@ StageMorph.prototype.blockTemplates = function (category) { txt.setColor(this.paletteTextColor); blocks.push(txt); blocks.push('-'); + blocks.push(block('reportCostumes')); + blocks.push('-'); blocks.push(block('log')); blocks.push(block('alert')); } @@ -4322,6 +4418,20 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(watcherToggle('getTempo')); blocks.push(block('getTempo')); + // for debugging: /////////////// + + if (this.world().isDevMode) { + blocks.push('-'); + txt = new TextMorph(localize( + 'development mode \ndebugging primitives:' + )); + txt.fontSize = 9; + txt.setColor(this.paletteTextColor); + blocks.push(txt); + blocks.push('-'); + blocks.push(block('reportSounds')); + } + } else if (cat === 'pen') { blocks.push(block('clear')); @@ -4352,9 +4462,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')); @@ -4398,6 +4513,8 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push('-'); blocks.push(block('reportIsFastTracking')); blocks.push(block('doSetFastTracking')); + blocks.push('-'); + blocks.push(block('reportDate')); // for debugging: /////////////// @@ -4773,6 +4890,9 @@ StageMorph.prototype.doWearPreviousCostume StageMorph.prototype.doSwitchToCostume = SpriteMorph.prototype.doSwitchToCostume; +StageMorph.prototype.reportCostumes + = SpriteMorph.prototype.reportCostumes; + // StageMorph graphic effects StageMorph.prototype.setEffect @@ -4814,6 +4934,9 @@ StageMorph.prototype.resumeAllActiveSounds = function () { }); }; +StageMorph.prototype.reportSounds + = SpriteMorph.prototype.reportSounds; + // StageMorph non-variable watchers StageMorph.prototype.toggleWatcher @@ -4940,6 +5063,12 @@ SpriteBubbleMorph.prototype.dataAsMorph = function (data) { contents.silentSetWidth(img.width); contents.silentSetHeight(img.height); contents.image = img; + } else if (data instanceof Costume) { + img = data.thumbnail(new Point(40, 40)); + contents = new Morph(); + contents.silentSetWidth(img.width); + contents.silentSetHeight(img.height); + contents.image = img; } else if (data instanceof HTMLCanvasElement) { contents = new Morph(); contents.silentSetWidth(data.width); @@ -5147,7 +5276,7 @@ Costume.prototype.shrinkWrap = function () { }; Costume.prototype.boundingBox = function () { - // answer the rectangle surrounding my contents' non-transparent pixels + // answer the rectangle surrounding my contents' non-transparent pixels var row, col, pic = this.contents, @@ -5255,7 +5384,7 @@ Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) { editor.openIn( aWorld, isnew ? - newCanvas(new Point(480, 360)) : + newCanvas(StageMorph.prototype.dimensions) : this.contents, isnew ? new Point(240, 180) : @@ -5263,7 +5392,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) { @@ -5600,17 +5732,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 }; @@ -5618,17 +5754,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; } }; @@ -5769,6 +5911,12 @@ CellMorph.prototype.drawNew = function () { this.contentsMorph.silentSetWidth(img.width); this.contentsMorph.silentSetHeight(img.height); this.contentsMorph.image = img; + } else if (this.contents instanceof Costume) { + img = this.contents.thumbnail(new Point(40, 40)); + this.contentsMorph = new Morph(); + this.contentsMorph.silentSetWidth(img.width); + this.contentsMorph.silentSetHeight(img.height); + this.contentsMorph.image = img; } else if (this.contents instanceof List) { if (this.isCircular()) { this.contentsMorph = new TextMorph( @@ -6494,7 +6642,7 @@ StagePrompterMorph.prototype.init = function (question) { if (this.label) {this.add(this.label); } this.add(this.inputField); this.add(this.button); - this.setWidth(480 - 20); + this.setWidth(StageMorph.prototype.dimensions.x - 20); this.fixLayout(); }; @@ -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,188 @@ 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) + Feb 11 - dynamically adjust to stage dimensions (Jens) + + */ - */
-
-/*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, StageMorph + */ + // Global stuff //////////////////////////////////////////////////////// -modules.paint = '2013-September-16'; +modules.paint = '2014-February-11'; // 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(StageMorph.prototype.dimensions); + + 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 +246,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 +442,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 +648,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 +692,206 @@ 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 % width > 1) { + stack.push(currentpoint + 1); + stack.push(currentpoint - 1); + } + if (currentpoint > 0 && currentpoint < height * width) { + 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 + width = this.paper.width; + + 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 < width; i += 1) { + mctx.lineTo( + i, + (2 * h) * Math.sqrt(2 - Math.pow( + (i - x) / (2 * w), + 2 + )) + y + ); + } + for (i = width; 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 +910,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-13'; // XML_Serializer /////////////////////////////////////////////////////// @@ -377,7 +377,18 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode) { project.pentrails.src = model.pentrails.contents; } project.stage.setTempo(model.stage.attributes.tempo); + StageMorph.prototype.dimensions = new Point(480, 360); + if (model.stage.attributes.width) { + StageMorph.prototype.dimensions.x = + Math.max(+model.stage.attributes.width, 480); + } + if (model.stage.attributes.height) { + StageMorph.prototype.dimensions.y = + Math.max(+model.stage.attributes.height, 180); + } 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 = @@ -1339,7 +1350,9 @@ StageMorph.prototype.toXML = function (serializer) { '<project name="@" app="@" version="@">' + '<notes>$</notes>' + '<thumbnail>$</thumbnail>' + - '<stage name="@" costume="@" tempo="@" threadsafe="@" ' + + '<stage name="@" width="@" height="@" ' + + 'costume="@" tempo="@" threadsafe="@" ' + + 'lines="@" ' + 'codify="@" ' + 'scheduled="@" ~>' + '<pentrails>$</pentrails>' + @@ -1361,9 +1374,12 @@ StageMorph.prototype.toXML = function (serializer) { (ide && ide.projectNotes) ? ide.projectNotes : '', thumbdata, this.name, + StageMorph.prototype.dimensions.x, + StageMorph.prototype.dimensions.y, 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 = '2013-December-11'; +modules.threads = '2014-Feb-10'; var ThreadManager; var Process; @@ -111,7 +111,7 @@ function snapEquals(a, b) { y = b; } - // handle text comparision text-insensitive. + // handle text comparision case-insensitive. if (isString(x) && isString(y)) { return x.toLowerCase() === y.toLowerCase(); } @@ -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) { @@ -2474,6 +2536,35 @@ Process.prototype.reportTimer = function () { return 0; }; +// Process Dates and times in Snap +// Map block options to built-in functions +var dateMap = { + 'year' : 'getFullYear', + 'month' : 'getMonth', + 'date': 'getDate', + 'day of week' : 'getDay', + 'hour' : 'getHours', + 'minute' : 'getMinutes', + 'second' : 'getSeconds', + 'time in milliseconds' : 'getTime' +}; + +Process.prototype.reportDate = function (datefn) { + var inputFn = this.inputOption(datefn), + currDate = new Date(), + func = dateMap[inputFn], + result = currDate[func](); + + if (!dateMap[inputFn]) { return ''; } + + // Show months as 1-12 and days as 1-7 + if (inputFn === 'month' || inputFn === 'day of week') { + result += 1; + } + + return result; +}; + // Process code mapping /* @@ -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-February-13'; var PushButtonMorph; var ToggleButtonMorph; @@ -1760,6 +1760,113 @@ DialogBoxMorph.prototype.promptCode = function ( text.edit(); }; +DialogBoxMorph.prototype.promptVector = function ( + title, + point, + deflt, + xLabel, + yLabel, + world, + pic, + msg +) { + var vec = new AlignmentMorph('row', 4), + xInp = new InputFieldMorph(point.x.toString(), true), + yInp = new InputFieldMorph(point.y.toString(), true), + xCol = new AlignmentMorph('column', 2), + yCol = new AlignmentMorph('column', 2), + inp = new AlignmentMorph('column', 2), + bdy = new AlignmentMorph('column', this.padding); + + function labelText(string) { + return new TextMorph( + localize(string), + 10, + null, // style + false, // bold + null, // italic + null, // alignment + null, // width + null, // font name + MorphicPreferences.isFlat ? null : new Point(1, 1), + new Color(255, 255, 255) // shadowColor + ); + } + + inp.alignment = 'left'; + inp.setColor(this.color); + bdy.setColor(this.color); + xCol.alignment = 'left'; + xCol.setColor(this.color); + yCol.alignment = 'left'; + yCol.setColor(this.color); + + xCol.add(labelText(xLabel)); + xCol.add(xInp); + yCol.add(labelText(yLabel)); + yCol.add(yInp); + vec.add(xCol); + vec.add(yCol); + inp.add(vec); + + if (msg) { + bdy.add(labelText(msg)); + } + + bdy.add(inp); + + vec.fixLayout(); + xCol.fixLayout(); + yCol.fixLayout(); + inp.fixLayout(); + bdy.fixLayout(); + + this.labelString = title; + this.createLabel(); + if (pic) {this.setPicture(pic); } + + this.addBody(bdy); + + vec.drawNew(); + xCol.drawNew(); + xInp.drawNew(); + yCol.drawNew(); + yInp.drawNew(); + bdy.fixLayout(); + + this.addButton('ok', 'OK'); + + if (deflt instanceof Point) { + this.addButton( + function () { + xInp.setContents(deflt.x.toString()); + yInp.setContents(deflt.y.toString()); + }, + 'Default' + + ); + } + + this.addButton('cancel', 'Cancel'); + this.fixLayout(); + this.drawNew(); + this.fixLayout(); + + this.edit = function () { + xInp.edit(); + }; + + this.getInput = function () { + return new Point(xInp.getValue(), yInp.getValue()); + }; + + if (!this.key) { + this.key = 'vector' + title; + } + + this.popUp(world); +}; + DialogBoxMorph.prototype.promptCredentials = function ( title, purpose, @@ -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: |
