summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blocks.js30
-rw-r--r--byob.js39
-rw-r--r--gui.js61
-rwxr-xr-xhistory.txt6
-rw-r--r--objects.js165
5 files changed, 284 insertions, 17 deletions
diff --git a/blocks.js b/blocks.js
index 69ae610..b2955e9 100644
--- a/blocks.js
+++ b/blocks.js
@@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2014-May-02';
+modules.blocks = '2014-June-04';
var SyntaxElementMorph;
@@ -913,17 +913,13 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
part = new InputSlotMorph(
null,
false,
- {
- /*
- color : 'color',
- fisheye : 'fisheye',
- whirl : 'whirl',
- pixelate : 'pixelate',
- mosaic : 'mosaic',
- brightness : 'brightness',
- */
- ghost : ['ghost']
- },
+ { brightness : ['brightness'],
+ ghost : ['ghost'],
+ negative : ['negative'],
+ comic: ['comic'],
+ duplicate: ['duplicate'],
+ confetti: ['confetti']
+ },
true
);
part.setContents(['ghost']);
@@ -4957,6 +4953,14 @@ ScriptsMorph.prototype.cleanUp = function () {
};
ScriptsMorph.prototype.exportScriptsPicture = function () {
+ var pic = this.scriptsPicture();
+ if (pic) {
+ window.open(pic.toDataURL());
+ }
+};
+
+ScriptsMorph.prototype.scriptsPicture = function () {
+ // private - answer a canvas containing the pictures of all scripts
var boundingBox, pic, ctx;
if (this.children.length === 0) {return; }
boundingBox = this.children[0].fullBounds();
@@ -4977,7 +4981,7 @@ ScriptsMorph.prototype.exportScriptsPicture = function () {
);
}
});
- window.open(pic.toDataURL());
+ return pic;
};
ScriptsMorph.prototype.addComment = function () {
diff --git a/byob.js b/byob.js
index 6a10110..0f79acf 100644
--- a/byob.js
+++ b/byob.js
@@ -106,7 +106,7 @@ SymbolMorph, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.byob = '2014-May-02';
+modules.byob = '2014-Jun-04';
// Declarations
@@ -336,6 +336,43 @@ CustomBlockDefinition.prototype.parseSpec = function (spec) {
return parts;
};
+// CustomBlockDefinition picturing
+
+CustomBlockDefinition.prototype.scriptsPicture = function () {
+ var scripts, proto, block, comment;
+
+ scripts = new ScriptsMorph();
+ scripts.cleanUpMargin = 10;
+ proto = new PrototypeHatBlockMorph(this);
+ proto.setPosition(scripts.position().add(10));
+ if (this.comment !== null) {
+ comment = this.comment.fullCopy();
+ proto.comment = comment;
+ comment.block = proto;
+ }
+ if (this.body !== null) {
+ proto.nextBlock(this.body.expression.fullCopy());
+ }
+ scripts.add(proto);
+ proto.fixBlockColor(null, true);
+ this.scripts.forEach(function (element) {
+ block = element.fullCopy();
+ block.setPosition(scripts.position().add(element.position()));
+ scripts.add(block);
+ if (block instanceof BlockMorph) {
+ block.allComments().forEach(function (comment) {
+ comment.align(block);
+ });
+ }
+ });
+ proto.allComments().forEach(function (comment) {
+ comment.align(proto);
+ });
+ proto.children[0].fixLayout();
+ scripts.fixMultiArgs();
+ return scripts.scriptsPicture();
+};
+
// CustomCommandBlockMorph /////////////////////////////////////////////
// CustomCommandBlockMorph inherits from CommandBlockMorph:
diff --git a/gui.js b/gui.js
index 981696a..67510cf 100644
--- a/gui.js
+++ b/gui.js
@@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2014-May-26';
+modules.gui = '2014-Jun-04';
// Declarations
@@ -2350,6 +2350,15 @@ IDE_Morph.prototype.projectMenu = function () {
'show global custom block definitions as XML\nin a new browser window'
);
+ if (shiftClicked) {
+ menu.addItem(
+ 'Export all scripts as pic...',
+ function () {myself.exportScriptsPicture(); },
+ 'show a picture of all scripts\nand block definitions',
+ new Color(100, 0, 0)
+ );
+ }
+
menu.addLine();
menu.addItem(
'Import tools',
@@ -2847,6 +2856,56 @@ IDE_Morph.prototype.exportSprite = function (sprite) {
+ '</sprites>');
};
+IDE_Morph.prototype.exportScriptsPicture = function () {
+ var pics = [],
+ pic,
+ padding = 20,
+ w = 0,
+ h = 0,
+ y = 0,
+ ctx;
+
+ // collect all script pics
+ this.sprites.asArray().forEach(function (sprite) {
+ pics.push(sprite.image);
+ pics.push(sprite.scripts.scriptsPicture());
+ sprite.customBlocks.forEach(function (def) {
+ pics.push(def.scriptsPicture());
+ });
+ });
+ pics.push(this.stage.image);
+ pics.push(this.stage.scripts.scriptsPicture());
+ this.stage.customBlocks.forEach(function (def) {
+ pics.push(def.scriptsPicture());
+ });
+
+ // collect global block pics
+ this.stage.globalBlocks.forEach(function (def) {
+ pics.push(def.scriptsPicture());
+ });
+
+ pics = pics.filter(function (each) {return !isNil(each); });
+
+ // determine dimensions of composite
+ pics.forEach(function (each) {
+ w = Math.max(w, each.width);
+ h += (each.height);
+ h += padding;
+ });
+ h -= padding;
+ pic = newCanvas(new Point(w, h));
+ ctx = pic.getContext('2d');
+
+ // draw all parts
+ pics.forEach(function (each) {
+ ctx.drawImage(each, 0, y);
+ y += padding;
+ y += each.height;
+ });
+
+ window.open(pic.toDataURL());
+};
+
IDE_Morph.prototype.openProjectString = function (str) {
var msg,
myself = this;
diff --git a/history.txt b/history.txt
index bd4d9fe..a72aa2c 100755
--- a/history.txt
+++ b/history.txt
@@ -2139,3 +2139,9 @@ ______
* Objects: Fixed #445 (minor search + zoom issues)
* Localization additions and Portuguese translation update, thanks, Manuel!
* GUI, cloud: Show last-changed-timestamp when opening cloud projects
+
+140604
+------
+* Blocks: refactor “script pics” feature
+* BYOB: new scriptsPicture() method for custom block definitions
+* GUI: new (hidden) feature: “Export all scripts as pic” (including custom block refs)
diff --git a/objects.js b/objects.js
index 5f91606..81ce072 100644
--- a/objects.js
+++ b/objects.js
@@ -1292,6 +1292,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;
@@ -1421,6 +1433,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
@@ -1443,6 +1458,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(
@@ -2831,14 +2847,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 () {
@@ -2849,10 +2983,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);
};
@@ -4006,6 +4148,18 @@ StageMorph.prototype.init = function (globals) {
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;
@@ -4070,6 +4224,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);
}
};
@@ -5093,6 +5248,12 @@ StageMorph.prototype.reportCostumes
// StageMorph graphic effects
+StageMorph.prototype.graphicsChanged
+ = SpriteMorph.prototype.graphicsChanged;
+
+StageMorph.prototype.applyGraphicsEffects
+ = SpriteMorph.prototype.applyGraphicsEffects;
+
StageMorph.prototype.setEffect
= SpriteMorph.prototype.setEffect;