summaryrefslogtreecommitdiff
path: root/objects.js
diff options
context:
space:
mode:
authorViraj Mahesh <virajmahesh@gmail.com>2014-07-13 09:47:30 +0400
committerViraj Mahesh <virajmahesh@gmail.com>2014-07-13 09:47:30 +0400
commita7f0de880f691ef32553713187a1b2f3d0cf3756 (patch)
treefd51b3fffa40e04876a7e414f3a995c6a5afb96c /objects.js
parent7daaf1252a651271f170abc0a7a0f532778aad51 (diff)
parentec8b14a3758acfc852a6f02010394bd5814d7272 (diff)
downloadsnap-a7f0de880f691ef32553713187a1b2f3d0cf3756.tar.gz
snap-a7f0de880f691ef32553713187a1b2f3d0cf3756.zip
Merge branch 'master' into extensions
Conflicts: objects.js
Diffstat (limited to 'objects.js')
-rw-r--r--objects.js524
1 files changed, 502 insertions, 22 deletions
diff --git a/objects.js b/objects.js
index 4b1b359..002b7e3 100644
--- a/objects.js
+++ b/objects.js
@@ -61,6 +61,7 @@
sound handling
Achal Dave contributed research and prototyping for creating music
using the Web Audio API
+ Yuan Yuan contributed graphic effects for costumes
*/
@@ -124,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2014-February-11';
+modules.objects = '2014-Jun-06';
var SpriteMorph;
var StageMorph;
@@ -203,90 +204,106 @@ SpriteMorph.prototype.initBlocks = function () {
// Motion
forward: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'move %n steps',
defaults: [10]
},
turn: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'turn %clockwise %n degrees',
defaults: [15]
},
turnLeft: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'turn %counterclockwise %n degrees',
defaults: [15]
},
setHeading: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'point in direction %dir'
},
doFaceTowards: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'point towards %dst'
},
gotoXY: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'go to x: %n y: %n',
defaults: [0, 0]
},
doGotoObject: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'go to %dst'
},
doGlide: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'glide %n secs to x: %n y: %n',
defaults: [1, 0, 0]
},
changeXPosition: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'change x by %n',
defaults: [10]
},
setXPosition: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'set x to %n',
defaults: [0]
},
changeYPosition: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'change y by %n',
defaults: [10]
},
setYPosition: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'set y to %n',
defaults: [0]
},
bounceOffEdge: {
+ only: SpriteMorph,
type: 'command',
category: 'motion',
spec: 'if on edge, bounce'
},
xPosition: {
+ only: SpriteMorph,
type: 'reporter',
category: 'motion',
spec: 'x position'
},
yPosition: {
+ only: SpriteMorph,
type: 'reporter',
category: 'motion',
spec: 'y position'
},
direction: {
+ only: SpriteMorph,
type: 'reporter',
category: 'motion',
spec: 'direction'
@@ -309,24 +326,28 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'costume #'
},
doSayFor: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'say %s for %n secs',
defaults: [localize('Hello!'), 2]
},
bubble: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'say %s',
defaults: [localize('Hello!')]
},
doThinkFor: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'think %s for %n secs',
defaults: [localize('Hmm...'), 2]
},
doThink: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'think %s',
@@ -350,38 +371,45 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'clear graphic effects'
},
changeScale: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'change size by %n',
defaults: [10]
},
setScale: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'set size to %n %',
defaults: [100]
},
getScale: {
+ only: SpriteMorph,
type: 'reporter',
category: 'looks',
spec: 'size'
},
show: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'show'
},
hide: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'hide'
},
comeToFront: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'go to front'
},
goBack: {
+ only: SpriteMorph,
type: 'command',
category: 'looks',
spec: 'go back %n layers',
@@ -395,12 +423,21 @@ SpriteMorph.prototype.initBlocks = function () {
},
// Looks - Debugging primitives for development mode
+ reportCostumes: {
+ dev: true,
+ type: 'reporter',
+ category: 'looks',
+ spec: 'wardrobe'
+ },
+
alert: {
+ dev: true,
type: 'command',
category: 'looks',
spec: 'alert %mult%s'
},
log: {
+ dev: true,
type: 'command',
category: 'looks',
spec: 'console log %mult%s'
@@ -452,6 +489,14 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'tempo'
},
+ // Sound - Debugging primitives for development mode
+ reportSounds: {
+ dev: true,
+ type: 'reporter',
+ category: 'sound',
+ spec: 'jukebox'
+ },
+
// Pen
clear: {
type: 'command',
@@ -459,57 +504,67 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'clear'
},
down: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'pen down'
},
up: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'pen up'
},
setColor: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'set pen color to %clr'
},
changeHue: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'change pen color by %n',
defaults: [10]
},
setHue: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'set pen color to %n',
defaults: [0]
},
changeBrightness: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'change pen shade by %n',
defaults: [10]
},
setBrightness: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'set pen shade to %n',
defaults: [100]
},
changeSize: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'change pen size by %n',
defaults: [1]
},
setSize: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'set pen size to %n',
defaults: [1]
},
doStamp: {
+ only: SpriteMorph,
type: 'command',
category: 'pen',
spec: 'stamp'
@@ -703,31 +758,37 @@ SpriteMorph.prototype.initBlocks = function () {
// Sensing
reportTouchingObject: {
+ only: SpriteMorph,
type: 'predicate',
category: 'sensing',
spec: 'touching %col ?'
},
reportTouchingColor: {
+ only: SpriteMorph,
type: 'predicate',
category: 'sensing',
spec: 'touching %clr ?'
},
reportColorIsTouchingColor: {
+ only: SpriteMorph,
type: 'predicate',
category: 'sensing',
spec: 'color %clr is touching %clr ?'
},
colorFiltered: {
+ dev: true,
type: 'reporter',
category: 'sensing',
spec: 'filtered for %clr'
},
reportStackSize: {
+ dev: true,
type: 'reporter',
category: 'sensing',
spec: 'stack size'
},
reportFrameCount: {
+ dev: true,
type: 'reporter',
category: 'sensing',
spec: 'frames'
@@ -739,6 +800,7 @@ SpriteMorph.prototype.initBlocks = function () {
defaults: [localize('what\'s your name?')]
},
reportLastAnswer: { // retained for legacy compatibility
+ dev: true,
type: 'reporter',
category: 'sensing',
spec: 'answer'
@@ -779,6 +841,7 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'reset timer'
},
reportTimer: { // retained for legacy compatibility
+ dev: true,
type: 'reporter',
category: 'sensing',
spec: 'timer'
@@ -962,12 +1025,14 @@ SpriteMorph.prototype.initBlocks = function () {
defaults: [localize('hello') + ' ' + localize('world'), " "]
},
reportTypeOf: { // only in dev mode for debugging
+ dev: true,
type: 'reporter',
category: 'operators',
spec: 'type of %s',
defaults: [5]
},
reportTextFunction: { // only in dev mode - experimental
+ dev: true,
type: 'reporter',
category: 'operators',
spec: '%txtfun of %s',
@@ -1076,6 +1141,7 @@ SpriteMorph.prototype.initBlocks = function () {
// MAP - experimental
reportMap: {
+ dev: true,
type: 'reporter',
category: 'lists',
spec: 'map %repRing over %l'
@@ -1139,10 +1205,10 @@ SpriteMorph.prototype.blockAlternatives = {
yPosition: ['xPosition'],
// looks:
- doSayFor: ['doThinkFor'],
- doThinkFor: ['doSayFor'],
- bubble: ['doThink'],
- doThink: ['bubble'],
+ doSayFor: ['doThinkFor', 'bubble', 'doThink', 'doAsk'],
+ doThinkFor: ['doSayFor', 'doThink', 'bubble', 'doAsk'],
+ bubble: ['doThink', 'doAsk', 'doSayFor', 'doThinkFor'],
+ doThink: ['bubble', 'doAsk', 'doSayFor', 'doThinkFor'],
show: ['hide'],
hide: ['show'],
changeEffect: ['setEffect'],
@@ -1173,8 +1239,13 @@ SpriteMorph.prototype.blockAlternatives = {
receiveClick: ['receiveGo'],
doBroadcast: ['doBroadcastAndWait'],
doBroadcastAndWait: ['doBroadcast'],
+ doIf: ['doIfElse', 'doUntil'],
+ doIfElse: ['doIf', 'doUntil'],
+ doRepeat: ['doUntil'],
+ doUntil: ['doRepeat', 'doIf'],
// sensing:
+ doAsk: ['bubble', 'doThink', 'doSayFor', 'doThinkFor'],
getLastAnswer: ['getTimer'],
getTimer: ['getLastAnswer'],
reportMouseX: ['reportMouseY'],
@@ -1233,6 +1304,18 @@ SpriteMorph.prototype.init = function (globals) {
this.idx = 0; // not to be serialized (!) - used for de-serialization
this.wasWarped = false; // not to be serialized, used for fast-tracking
+ this.graphicsValues = { 'negative': 0,
+ 'fisheye': 0,
+ 'whirl': 0,
+ 'pixelate': 0,
+ 'mosaic': 0,
+ 'brightness': 0,
+ 'color': 0,
+ 'comic': 0,
+ 'duplicate': 0,
+ 'confetti': 0
+ };
+
SpriteMorph.uber.init.call(this);
this.isDraggable = true;
@@ -1364,6 +1447,9 @@ SpriteMorph.prototype.drawNew = function () {
ctx.rotate(radians(facing - 90));
ctx.drawImage(pic.contents, 0, 0);
+ // apply graphics effects to image
+ this.image = this.applyGraphicsEffects(this.image);
+
// adjust my position to the rotation
this.setCenter(currentCenter, true); // just me
@@ -1386,6 +1472,7 @@ SpriteMorph.prototype.drawNew = function () {
this.setCenter(currentCenter, true); // just me
SpriteMorph.uber.drawNew.call(this, facing);
this.rotationOffset = this.extent().divideBy(2);
+ this.image = this.applyGraphicsEffects(this.image);
if (isLoadingCostume) { // retry until costume is done loading
cst = this.costume;
handle = setInterval(
@@ -1630,6 +1717,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'));
}
@@ -1651,6 +1740,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'));
@@ -2049,6 +2152,7 @@ SpriteMorph.prototype.freshPalette = function (category) {
});
}
+ menu.addItem('find blocks...', function () {myself.searchBlocks(); });
if (canHidePrimitives()) {
menu.addItem(
'hide primitives',
@@ -2180,6 +2284,137 @@ SpriteMorph.prototype.freshPalette = function (category) {
return palette;
};
+// SpriteMorph blocks searching
+
+SpriteMorph.prototype.blocksMatching = function (searchString, strictly) {
+ // answer an array of block templates whose spec contains
+ // the given search string, ordered by descending relevance
+ var blocks = [],
+ blocksDict,
+ myself = this,
+ search = searchString.toLowerCase(),
+ stage = this.parentThatIsA(StageMorph);
+
+ function labelOf(aBlockSpec) {
+ var words = (BlockMorph.prototype.parseSpec(aBlockSpec)),
+ filtered = words.filter(
+ function (each) {return (each.indexOf('%') !== 0); }
+ );
+ return filtered.join(' ');
+ }
+
+ function fillDigits(anInt, totalDigits, fillChar) {
+ var ans = String(anInt);
+ while (ans.length < totalDigits) {ans = fillChar + ans; }
+ return ans;
+ }
+
+ function relevance(aBlockLabel, aSearchString) {
+ var lbl = ' ' + aBlockLabel,
+ idx = lbl.indexOf(aSearchString),
+ atWord;
+ if (idx === -1) {return -1; }
+ atWord = (lbl.charAt(idx - 1) === ' ');
+ if (strictly && !atWord) {return -1; }
+ return (atWord ? '1' : '2') + fillDigits(idx, 4, '0');
+ }
+
+ function primitive(selector) {
+ var newBlock = SpriteMorph.prototype.blockForSelector(selector, true);
+ newBlock.isTemplate = true;
+ return newBlock;
+ }
+
+ // custom blocks
+ [this.customBlocks, stage.globalBlocks].forEach(function (blocksList) {
+ blocksList.forEach(function (definition) {
+ var spec = localize(definition.blockSpec()).toLowerCase(),
+ rel = relevance(labelOf(spec), search);
+ if (rel !== -1) {
+ blocks.push([definition.templateInstance(), rel + '1']);
+ }
+ });
+ });
+ // primitives
+ blocksDict = SpriteMorph.prototype.blocks;
+ Object.keys(blocksDict).forEach(function (selector) {
+ if (!StageMorph.prototype.hiddenPrimitives[selector]) {
+ var block = blocksDict[selector],
+ spec = localize(block.spec).toLowerCase(),
+ rel = relevance(labelOf(spec), search);
+ if (
+ (rel !== -1) &&
+ (!block.dev) &&
+ (!block.only || (block.only === myself.constructor))
+ ) {
+ blocks.push([primitive(selector), rel + '2']);
+ }
+ }
+ });
+ blocks.sort(function (x, y) {return x[1] < y[1] ? -1 : 1; });
+ return blocks.map(function (each) {return each[0]; });
+};
+
+SpriteMorph.prototype.searchBlocks = function () {
+ var myself = this,
+ unit = SyntaxElementMorph.prototype.fontSize,
+ ide = this.parentThatIsA(IDE_Morph),
+ oldSearch = '',
+ searchBar = new InputFieldMorph(''),
+ searchPane = ide.createPalette('forSearch');
+
+ function show(blocks) {
+ var oldFlag = Morph.prototype.trackChanges,
+ x = searchPane.contents.left() + 5,
+ y = (searchBar.bottom() + unit);
+ Morph.prototype.trackChanges = false;
+ searchPane.contents.children = [searchPane.contents.children[0]];
+ blocks.forEach(function (block) {
+ block.setPosition(new Point(x, y));
+ searchPane.addContents(block);
+ y += block.height();
+ y += unit * 0.3;
+ });
+ Morph.prototype.trackChanges = oldFlag;
+ searchPane.changed();
+ }
+
+ searchPane.owner = this;
+ searchPane.color = myself.paletteColor;
+ searchPane.contents.color = myself.paletteColor;
+ searchPane.addContents(searchBar);
+ searchBar.drawNew();
+ searchBar.setWidth(ide.logo.width() - 30);
+ searchBar.contrast = 90;
+ searchBar.setPosition(
+ searchPane.contents.topLeft().add(new Point(10, 10))
+ );
+ searchBar.drawNew();
+
+ searchPane.accept = function () {
+ var search = searchBar.getValue();
+ if (search.length > 0) {
+ show(myself.blocksMatching(search));
+ }
+ };
+
+ searchPane.reactToKeystroke = function () {
+ var search = searchBar.getValue();
+ if (search !== oldSearch) {
+ oldSearch = search;
+ show(myself.blocksMatching(search, search.length < 2));
+ }
+ };
+
+ searchBar.cancel = function () {
+ ide.refreshPalette();
+ ide.palette.adjustScrollBars();
+ };
+
+ ide.fixLayout('refreshPalette');
+ searchBar.edit();
+};
+
// SpriteMorph variable management
SpriteMorph.prototype.addVariable = function (name, isGlobal) {
@@ -2272,6 +2507,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;
@@ -2302,6 +2542,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) {
@@ -2327,6 +2571,10 @@ SpriteMorph.prototype.playSound = function (name) {
}
};
+SpriteMorph.prototype.reportSounds = function () {
+ return this.sounds;
+};
+
// SpriteMorph user menu
SpriteMorph.prototype.userMenu = function () {
@@ -2615,14 +2863,132 @@ SpriteMorph.prototype.changeScale = function (delta) {
this.setScale(this.getScale() + (+delta || 0));
};
-// SpriteMorph graphic effects
+// Spritemorph graphic effects
+
+SpriteMorph.prototype.graphicsChanged = function () {
+ var myself = this;
+ return Object.keys(this.graphicsValues).some(
+ function (any) {
+ return myself.graphicsValues[any] < 0 ||
+ myself.graphicsValues[any] > 0;
+ }
+ );
+};
+
+SpriteMorph.prototype.applyGraphicsEffects = function (canvas) {
+// For every effect: apply transform of that effect(canvas, stored value)
+// The future: write more effects here
+ var ctx, imagedata, pixels, newimagedata;
+
+ function transform_negative(p, value) {
+ var i, rcom, gcom, bcom;
+ if (value !== 0) {
+ for (i = 0; i < p.length; i += 4) {
+ rcom = 255 - p[i];
+ gcom = 255 - p[i + 1];
+ bcom = 255 - p[i + 2];
+
+ if (p[i] < rcom) { //compare to the complement
+ p[i] += value;
+ } else if (p[i] > rcom) {
+ p[i] -= value;
+ }
+ if (p[i + 1] < gcom) {
+ p[i + 1] += value;
+ } else if (p[i + 1] > gcom) {
+ p[i + 1] -= value;
+ }
+ if (p[i + 2] < bcom) {
+ p[i + 2] += value;
+ } else if (p[i + 2] > bcom) {
+ p[i + 2] -= value;
+ }
+ }
+ }
+ return p;
+ }
+
+ function transform_brightness(p, value) {
+ var i;
+ if (value !== 0) {
+ for (i = 0; i < p.length; i += 4) {
+ p[i] += value; //255 = 100% of this color
+ p[i + 1] += value;
+ p[i + 2] += value;
+ }
+ }
+ return p;
+ }
+
+ function transform_comic(p, value) {
+ var i;
+ if (value !== 0) {
+ for (i = 0; i < p.length; i += 4) {
+ p[i] += Math.sin(i * value) * 127 + 128;
+ p[i + 1] += Math.sin(i * value) * 127 + 128;
+ p[i + 2] += Math.sin(i * value) * 127 + 128;
+ }
+ }
+ return p;
+ }
+
+ function transform_duplicate(p, value) {
+ var i;
+ if (value !== 0) {
+ for (i = 0; i < p.length; i += 4) {
+ p[i] = p[i * value];
+ p[i + 1] = p[i * value + 1];
+ p[i + 2] = p[i * value + 2];
+ p[i + 3] = p[i * value + 3];
+ }
+ }
+ return p;
+ }
+
+ function transform_confetti(p, value) {
+ var i;
+ if (value !== 0) {
+ for (i = 0; i < p.length; i += 1) {
+ p[i] = Math.sin(value * p[i]) * 127 + p[i];
+ }
+ }
+ return p;
+ }
+
+ if (this.graphicsChanged()) {
+ ctx = canvas.getContext("2d");
+ imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ pixels = imagedata.data;
+
+ //A sprite should wear all 7 effects at once
+ /*pixels = transform_whirl(pixels, this.graphicsValues.whirl);*/
+ pixels = transform_negative(pixels, this.graphicsValues.negative);
+ pixels = transform_brightness(pixels, this.graphicsValues.brightness);
+ pixels = transform_comic(pixels, this.graphicsValues.comic);
+ /*pixels = transform_pixelate(pixels, this.graphicsValues.pixelate);*/
+ pixels = transform_duplicate(pixels, this.graphicsValues.duplicate);
+ /*pixels = transform_color(pixels, this.graphicsValues.color);*/
+ /*pixels = transform_fisheye(pixels, this.graphicsValues.fisheye);*/
+ pixels = transform_confetti(pixels, this.graphicsValues.confetti);
+
+ //the last object will have all the transformations done on it
+ newimagedata = ctx.createImageData(imagedata); //make imgdata object
+ newimagedata.data.set(pixels); //add transformed pixels
+ ctx.putImageData(newimagedata, 0, 0);
+ }
+
+ return canvas;
+};
SpriteMorph.prototype.setEffect = function (effect, value) {
var eff = effect instanceof Array ? effect[0] : null;
if (eff === 'ghost') {
this.alpha = 1 - Math.min(Math.max(+value || 0, 0), 100) / 100;
- this.changed();
+ } else {
+ this.graphicsValues[eff] = value;
}
+ this.drawNew();
+ this.changed();
};
SpriteMorph.prototype.getGhostEffect = function () {
@@ -2633,10 +2999,18 @@ SpriteMorph.prototype.changeEffect = function (effect, value) {
var eff = effect instanceof Array ? effect[0] : null;
if (eff === 'ghost') {
this.setEffect(effect, this.getGhostEffect() + (+value || 0));
+ } else {
+ this.setEffect(effect, this.graphicsValues[eff] + value);
}
};
SpriteMorph.prototype.clearEffects = function () {
+ var effect;
+ for (effect in this.graphicsValues) {
+ if (this.graphicsValues.hasOwnProperty(effect)) {
+ this.setEffect([effect], 0);
+ }
+ }
this.setEffect(['ghost'], 0);
};
@@ -2845,11 +3219,12 @@ SpriteMorph.prototype.forward = function (steps) {
SpriteMorph.prototype.setHeading = function (degrees) {
var x = this.xPosition(),
y = this.yPosition(),
- turn = degrees - this.heading;
+ dir = (+degrees || 0),
+ turn = dir - this.heading;
// apply to myself
this.changed();
- SpriteMorph.uber.setHeading.call(this, degrees);
+ SpriteMorph.uber.setHeading.call(this, dir);
this.silentGotoXY(x, y, true); // just me
this.positionTalkBubble();
@@ -3832,12 +4207,24 @@ StageMorph.prototype.init = function (globals) {
this.keysPressed = {}; // for handling keyboard events, do not persist
this.blocksCache = {}; // not to be serialized (!)
this.paletteCache = {}; // not to be serialized (!)
- this.lastAnswer = null; // last user input, do not persist
+ this.lastAnswer = ''; // last user input, do not persist
this.activeSounds = []; // do not persist
this.trailsCanvas = null;
this.isThreadSafe = false;
+ this.graphicsValues = { 'negative': 0,
+ 'fisheye': 0,
+ 'whirl': 0,
+ 'pixelate': 0,
+ 'mosaic': 0,
+ 'brightness': 0,
+ 'color': 0,
+ 'comic': 0,
+ 'duplicate': 0,
+ 'confetti': 0
+ };
+
StageMorph.uber.init.call(this);
this.acceptsDrops = false;
@@ -3904,6 +4291,7 @@ StageMorph.prototype.drawNew = function () {
(this.width() / this.scale - this.costume.width()) / 2,
(this.height() / this.scale - this.costume.height()) / 2
);
+ this.image = this.applyGraphicsEffects(this.image);
}
};
@@ -4228,6 +4616,9 @@ StageMorph.prototype.processKeyEvent = function (event, action) {
break;
default:
keyName = String.fromCharCode(event.keyCode || event.charCode);
+ if (event.ctrlKey || event.metaKey) {
+ keyName = 'ctrl ' + (event.shiftKey ? 'shift ' : '') + keyName;
+ }
}
action.call(this, keyName);
};
@@ -4242,6 +4633,18 @@ StageMorph.prototype.fireKeyEvent = function (key) {
if (evt === 'ctrl enter') {
return this.fireGreenFlagEvent();
}
+ if (evt === 'ctrl f') {
+ return this.parentThatIsA(IDE_Morph).currentSprite.searchBlocks();
+ }
+ if (evt === 'ctrl o') {
+ return this.parentThatIsA(IDE_Morph).openProjectsBrowser();
+ }
+ if (evt === 'ctrl s') {
+ return this.parentThatIsA(IDE_Morph).save();
+ }
+ if (evt === 'ctrl shift s') {
+ return this.parentThatIsA(IDE_Morph).saveProjectsBrowser();
+ }
if (evt === 'esc') {
return this.fireStopAllEvent();
}
@@ -4402,7 +4805,12 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('setEffect'));
blocks.push(block('clearEffects'));
blocks.push('-');
+<<<<<<< HEAD
blocks.push(block('doScreenshot'));
+=======
+ blocks.push(block('show'));
+ blocks.push(block('hide'));
+>>>>>>> master
// for debugging: ///////////////
@@ -4415,6 +4823,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'));
}
@@ -4436,6 +4846,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'));
@@ -4839,6 +5263,23 @@ StageMorph.prototype.thumbnail = function (extentPoint, excludedSprite) {
return trg;
};
+// StageMorph hiding and showing:
+
+/*
+ override the inherited behavior to recursively hide/show all
+ children.
+*/
+
+StageMorph.prototype.hide = function () {
+ this.isVisible = false;
+ this.changed();
+};
+
+StageMorph.prototype.show = function () {
+ this.isVisible = true;
+ this.changed();
+};
+
// StageMorph cloning overrice
StageMorph.prototype.createClone = nop;
@@ -4851,6 +5292,8 @@ StageMorph.prototype.paletteColor = SpriteMorph.prototype.paletteColor;
StageMorph.prototype.setName = SpriteMorph.prototype.setName;
StageMorph.prototype.palette = SpriteMorph.prototype.palette;
StageMorph.prototype.freshPalette = SpriteMorph.prototype.freshPalette;
+StageMorph.prototype.blocksMatching = SpriteMorph.prototype.blocksMatching;
+StageMorph.prototype.searchBlocks = SpriteMorph.prototype.searchBlocks;
StageMorph.prototype.showingWatcher = SpriteMorph.prototype.showingWatcher;
StageMorph.prototype.addVariable = SpriteMorph.prototype.addVariable;
StageMorph.prototype.deleteVariable = SpriteMorph.prototype.deleteVariable;
@@ -4900,8 +5343,17 @@ StageMorph.prototype.doWearPreviousCostume
StageMorph.prototype.doSwitchToCostume
= SpriteMorph.prototype.doSwitchToCostume;
+StageMorph.prototype.reportCostumes
+ = SpriteMorph.prototype.reportCostumes;
+
// StageMorph graphic effects
+StageMorph.prototype.graphicsChanged
+ = SpriteMorph.prototype.graphicsChanged;
+
+StageMorph.prototype.applyGraphicsEffects
+ = SpriteMorph.prototype.applyGraphicsEffects;
+
StageMorph.prototype.setEffect
= SpriteMorph.prototype.setEffect;
@@ -4941,6 +5393,9 @@ StageMorph.prototype.resumeAllActiveSounds = function () {
});
};
+StageMorph.prototype.reportSounds
+ = SpriteMorph.prototype.reportSounds;
+
// StageMorph non-variable watchers
StageMorph.prototype.toggleWatcher
@@ -5067,6 +5522,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);
@@ -5909,6 +6370,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(
@@ -6220,9 +6687,11 @@ WatcherMorph.prototype.update = function () {
} else {
newValue = this.target[this.getter]();
}
- num = +newValue;
- if (typeof newValue !== 'boolean' && !isNaN(num)) {
- newValue = Math.round(newValue * 1000000000) / 1000000000;
+ if (newValue !== '' && !isNil(newValue)) {
+ num = +newValue;
+ if (typeof newValue !== 'boolean' && !isNaN(num)) {
+ newValue = Math.round(newValue * 1000000000) / 1000000000;
+ }
}
if (newValue !== this.currentValue) {
this.changed();
@@ -6442,7 +6911,17 @@ WatcherMorph.prototype.userMenu = function () {
inp.addEventListener(
"change",
function () {
- var file, i;
+ var file;
+
+ function txtOnlyMsg(ftype) {
+ ide.inform(
+ 'Unable to import',
+ 'Snap! can only import "text" files.\n' +
+ 'You selected a file of type "' +
+ ftype +
+ '".'
+ );
+ }
function readText(aFile) {
var frd = new FileReader();
@@ -6452,18 +6931,19 @@ WatcherMorph.prototype.userMenu = function () {
e.target.result
);
};
- frd.readAsText(aFile);
+
+ if (aFile.type.indexOf("text") === 0) {
+ frd.readAsText(aFile);
+ } else {
+ txtOnlyMsg(aFile.type);
+ }
}
document.body.removeChild(inp);
ide.filePicker = null;
if (inp.files.length > 0) {
- for (i = 0; i < inp.files.length; i += 1) {
- file = inp.files[i];
- if (file.type.indexOf("text") === 0) {
- readText(file);
- }
- }
+ file = inp.files[inp.files.length - 1];
+ readText(file);
}
},
false
@@ -6479,7 +6959,7 @@ WatcherMorph.prototype.userMenu = function () {
'export...',
function () {
window.open(
- 'data:text/plain,' +
+ 'data:text/plain;charset=utf-8,' +
encodeURIComponent(this.currentValue.toString())
);
}