// Copyright (c) 2014-16 Walter Bender
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the 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.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
|
|
|
//The ProtoBlock class is defined in this file. Protoblocks are the prototypes
|
|
//from which Blocks are created.
|
|
|
|
// Protoblock contain generic information about blocks and some
|
|
// methods common to all blocks.
|
|
function ProtoBlock(name) {
|
|
// Name is used run-dictionary index, and palette label.
|
|
this.name = name;
|
|
// The palette to which this block is assigned.
|
|
this.palette = null;
|
|
// The graphic style used by the block.
|
|
this.style = null;
|
|
// The generator function used to create the artwork
|
|
this.generator = null;
|
|
// Does the block expand (or collapse) when other blocks are
|
|
// attached? e.g., start, repeat...
|
|
this.expandable = false;
|
|
// Is this block a parameter? Parameters have their labels
|
|
// overwritten with their current value.
|
|
this.parameter = false;
|
|
// How many "non-flow" arguments does a block have? (flow is
|
|
// vertical down a stack; args are horizontal. The pendown block
|
|
// has 0 args; the forward block has 1 arg; the setxy block has 2
|
|
// args.
|
|
this.args = 0;
|
|
// Default values for block parameters, e.g., forward 100 or right 90.
|
|
this.defaults = [];
|
|
// What is the size of the block prior to any expansion?
|
|
this.size = 1.0;
|
|
// Dock types are a list of the types associated with the docking points.
|
|
this.dockTypes = [];
|
|
// Static labels are generated as part of the inline SVG.
|
|
this.staticLabels = [];
|
|
// Default fontsize used for static labels.
|
|
this.fontsize = null;
|
|
// Extra block width for long labels
|
|
this.extraWidth = 0;
|
|
// Block scale
|
|
this.scale = DEFAULTBLOCKSCALE;
|
|
// The filepath of the image.
|
|
this.image = null;
|
|
// Hidden: don't show on any palette
|
|
this.hidden = false;
|
|
// Disabled: use inactive colors
|
|
this.disabled = false;
|
|
//Stores the width of the text component
|
|
this.textWidth = 0;
|
|
|
|
this.adjustWidthToLabel = function () {
|
|
if (this.staticLabels.length === 0) {
|
|
return;
|
|
}
|
|
var c = new createjs.Container();
|
|
var text = new createjs.Text(this.staticLabels[0], this.fontSize + 'px Sans', '#000000');
|
|
c.addChild(text);
|
|
var b = c.getBounds();
|
|
this.textWidth = b.width;
|
|
this.extraWidth += Math.max(b.width - 30, 0);
|
|
};
|
|
|
|
// What follows are the initializations for different block
|
|
// styles.
|
|
|
|
// E.g., penup, pendown
|
|
this.zeroArgBlock = function () {
|
|
this.args = 0;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.zeroArgBlockGenerator;
|
|
};
|
|
|
|
this.zeroArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., hidden (used at end of clamp)
|
|
this.hiddenBlockFlow = function () {
|
|
this.args = 0;
|
|
this.size = 0;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.hiddenBlockFlowGenerator;
|
|
};
|
|
|
|
// E.g., hidden (used at end of no flow clamp)
|
|
this.hiddenBlockNoFlow = function () {
|
|
this.args = 0;
|
|
this.size = 0;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('unavailable');
|
|
this.generator = this.hiddenBlockFlowGenerator;
|
|
};
|
|
|
|
this.hiddenBlockFlowGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(true);
|
|
svg.setTab(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
// We need to generate the artwork in order to generate the dock.
|
|
var artwork = svg.basicBlock();
|
|
// Then we replace the artwork with a single pixel.
|
|
var artwork = '<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><text style="font-size:10px;fill:#000000;font-family:sans-serif;text-anchor:end"><tspan x="46.333333333333336" y="13.5">block_label</tspan></text></svg>';
|
|
// And bring the last dock position to the top.
|
|
svg.docks[1][1] = svg.docks[0][1];
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., break
|
|
this.basicBlockNoFlow = function () {
|
|
this.args = 0;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('unavailable');
|
|
this.generator = this.basicBlockNoFlowGenerator;
|
|
};
|
|
|
|
this.basicBlockNoFlowGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(true);
|
|
svg.setTail(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., collapsed
|
|
this.basicBlockCollapsed = function () {
|
|
this.args = 0;
|
|
this.dockTypes.push('unavailable');
|
|
this.dockTypes.push('unavailable');
|
|
this.generator = this.basicBlockCollapsedGenerator;
|
|
};
|
|
|
|
this.basicBlockCollapsedGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setCap(true);
|
|
svg.setTail(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., forward, right
|
|
this.oneArgBlock = function () {
|
|
this.args = 1;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.oneArgBlockGenerator;
|
|
};
|
|
|
|
this.oneArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setInnies([true]);
|
|
svg.setSlot(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., wait for
|
|
this.oneBooleanArgBlock = function () {
|
|
this.args = 1;
|
|
this.size = 2.6;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('booleanin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.oneBooleanArgBlockGenerator;
|
|
};
|
|
|
|
this.oneBooleanArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setBoolean(true);
|
|
svg.setClampCount(0);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., setxy. These are expandable.
|
|
this.twoArgBlock = function () {
|
|
this.expandable = true;
|
|
this.style = 'twoarg';
|
|
this.size = 2;
|
|
this.args = 2;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.twoArgBlockGenerator;
|
|
};
|
|
|
|
this.twoArgBlockGenerator = function (expandY) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setInnies([true, true]);
|
|
svg.setSlot(true);
|
|
if (expandY) {
|
|
svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
|
|
} else {
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., ??? These are expandable.
|
|
this.threeArgBlock = function () {
|
|
this.expandable = true;
|
|
this.style = 'twoarg';
|
|
this.size = 3;
|
|
this.args = 3;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.threeArgBlockGenerator;
|
|
};
|
|
|
|
this.threeArgBlockGenerator = function (expandY) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setInnies([true, true, true]);
|
|
svg.setSlot(true);
|
|
if (expandY) {
|
|
svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
|
|
} else {
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., sqrt, box
|
|
this.oneArgMathBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 1;
|
|
this.args = 1;
|
|
this.parameter = true;
|
|
this.dockTypes.push('numberout');
|
|
this.dockTypes.push('numberin');
|
|
this.generator = this.oneArgMathBlockGenerator;
|
|
};
|
|
|
|
this.oneArgMathBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(false);
|
|
svg.setInnies([true]);
|
|
svg.setOutie(true);
|
|
svg.setTab(false);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., plus, minus, multiply, divide, power. These are also expandable.
|
|
this.twoArgMathBlock = function () {
|
|
this.expandable = true;
|
|
this.style = 'arg';
|
|
this.size = 2;
|
|
this.args = 2;
|
|
this.parameter = true;
|
|
this.dockTypes.push('numberout');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.generator = this.twoArgMathBlockGenerator;
|
|
};
|
|
|
|
this.twoArgMathBlockGenerator = function (expandY) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(false);
|
|
svg.setInnies([true, true]);
|
|
svg.setOutie(true);
|
|
svg.setTab(false);
|
|
if (expandY) {
|
|
svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
|
|
} else {
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
//
|
|
this.threeArgMathBlock = function () {
|
|
this.expandable = true;
|
|
this.style = 'arg';
|
|
this.size = 3;
|
|
this.args = 3;
|
|
this.parameter = true;
|
|
this.dockTypes.push('numberout');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.generator = this.threeArgMathBlockGenerator;
|
|
};
|
|
|
|
this.threeArgMathBlockGenerator = function (expandY) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(false);
|
|
svg.setInnies([true, true, true]);
|
|
svg.setOutie(true);
|
|
svg.setTab(false);
|
|
if (expandY) {
|
|
svg.setExpand(30 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
|
|
} else {
|
|
svg.setExpand(30 + this.extraWidth, 0, 0, 0);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBlock();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., number, string. Value blocks get DOM textareas associated
|
|
// with them so their values can be edited by the user.
|
|
this.valueBlock = function () {
|
|
this.style = 'value';
|
|
this.size = 1;
|
|
this.args = 0;
|
|
this.dockTypes.push('numberout');
|
|
this.generator = this.valueBlockGenerator;
|
|
};
|
|
|
|
this.valueBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
// Extra room for parameter label
|
|
svg.setExpand(60 + this.extraWidth, 0, 0, 0);
|
|
svg.setOutie(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBox();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., media. Media blocks invoke a chooser and a thumbnail
|
|
// image is overlayed to represent the data associated with the
|
|
// block.
|
|
this.mediaBlock = function () {
|
|
this.style = 'value';
|
|
this.size = 2;
|
|
this.args = 0;
|
|
this.dockTypes.push('mediaout');
|
|
this.generator = this.mediaBlockGenerator;
|
|
};
|
|
|
|
this.mediaBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
// Extra room for graphics
|
|
svg.setExpand(60 + this.extraWidth, 23, 0, 0);
|
|
svg.setOutie(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBox();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., start. A "child" flow is docked in an expandable clamp.
|
|
// There are no additional arguments and no flow above or below.
|
|
this.stackClampZeroArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 1;
|
|
this.dockTypes.push('unavailable');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('unavailable');
|
|
this.generator = this.stackClampZeroArgBlockGenerator;
|
|
};
|
|
|
|
this.stackClampZeroArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setCap(true);
|
|
svg.setTail(true);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., emptyclamp. Unlike start, there is a flow above and below.
|
|
this.flowClampBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 2;
|
|
this.args = 1;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampBlockGenerator;
|
|
};
|
|
|
|
this.flowClampBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
|
|
svg.setSlot(true);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., repeat. Unlike action, there is a flow above and below.
|
|
this.flowClampOneArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 2;
|
|
this.args = 2;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampOneArgBlockGenerator;
|
|
};
|
|
|
|
this.flowClampOneArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setInnies([true]);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., tuplet, which takes two args plus an interior flow. There is a flow above and below.
|
|
this.flowClampTwoArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 3;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampTwoArgBlockGenerator;
|
|
};
|
|
|
|
this.flowClampTwoArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setInnies([true, true]);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
this.flowClampThreeArgBlock = function (){
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 4;
|
|
this.args = 4;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('textin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampThreeArgBlockGenerator;
|
|
};
|
|
|
|
this.flowClampThreeArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setInnies([true, true,true]);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., do with args: innies instead of interior slots.
|
|
this.argClampOneArgBlock = function () {
|
|
this.style = 'argclamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('textin');
|
|
this.dockTypes.push('anyin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.argClampOneArgBlockGenerator;
|
|
};
|
|
|
|
this.argClampOneArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setInnies([true]);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, [1]);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.argClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., calculate with args: innies instead of interior slots.
|
|
this.argClampOneArgMathBlock = function () {
|
|
this.style = 'argclamparg';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.dockTypes.push('anyout');
|
|
this.dockTypes.push('textin');
|
|
this.dockTypes.push('anyin');
|
|
this.generator = this.argClampOneArgMathBlockGenerator;
|
|
};
|
|
|
|
this.argClampOneArgMathBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setInnies([true]);
|
|
svg.setOutie(true);
|
|
svg.setTab(false);
|
|
svg.setSlot(false);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, [1]);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.argClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., named do with args: innies instead of interior slots.
|
|
this.argClampBlock = function () {
|
|
this.style = 'argclamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 1;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('anyin');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.argClampBlockGenerator;
|
|
};
|
|
|
|
this.argClampBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, [1]);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.argClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., named calculate with args: innies instead of interior slots.
|
|
this.argClampMathBlock = function () {
|
|
this.style = 'argclamparg';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 1;
|
|
this.dockTypes.push('anyout');
|
|
this.dockTypes.push('anyin');
|
|
this.generator = this.argClampMathBlockGenerator;
|
|
};
|
|
|
|
this.argClampMathBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setOutie(true);
|
|
svg.setTab(false);
|
|
svg.setSlot(false);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, [1]);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.argClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., if. A "child" flow is docked in an expandable clamp. The
|
|
// additional argument is a boolean. There is flow above and below.
|
|
this.flowClampBooleanArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('booleanin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampBooleanArgBlockGenerator;
|
|
};
|
|
|
|
this.flowClampBooleanArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setBoolean(true);
|
|
svg.setSlot(true);
|
|
svg.setExpand(this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., if then else. Two "child" flows are docked in expandable
|
|
// clamps. The additional argument is a boolean. There is flow
|
|
// above and below.
|
|
this.doubleFlowClampBooleanArgBlock = function () {
|
|
this.style = 'doubleclamp';
|
|
this.expandable = true;
|
|
this.size = 4;
|
|
this.args = 3;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('booleanin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.doubleFlowClampBooleanArgBlockGenerator;
|
|
};
|
|
|
|
this.doubleFlowClampBooleanArgBlockGenerator = function (bottomSlots, topSlots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setBoolean(true);
|
|
svg.setClampCount(2);
|
|
|
|
if (topSlots) {
|
|
svg.setClampSlots(0, topSlots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
|
|
if (bottomSlots) {
|
|
svg.setClampSlots(1, bottomSlots);
|
|
} else {
|
|
svg.setClampSlots(1, 1);
|
|
}
|
|
|
|
svg.setExpand(this.extraWidth, 0, 0, 0);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., forever. Unlike start, there is flow above and below.
|
|
this.flowClampZeroArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 2;
|
|
this.args = 1;
|
|
this.dockTypes.push('out');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.flowClampZeroArgBlockGenerator;
|
|
};
|
|
|
|
this.flowClampZeroArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setTab(true);
|
|
svg.setSlot(true);
|
|
svg.setExpand(10 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., count clamp: math block with interior slots
|
|
this.argFlowClampBlock = function () {
|
|
this.style = 'argflowclamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.dockTypes.push('anyout');
|
|
this.dockTypes.push('in');
|
|
this.generator = this.argFlowClampGenerator;
|
|
};
|
|
|
|
this.argFlowClampGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setSlot(false);
|
|
svg.setOutie(true);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, [1]);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., action. A "child" flow is docked in an expandable clamp.
|
|
// The additional argument is a name. Again, no flow above or below.
|
|
this.stackClampOneArgBlock = function () {
|
|
this.style = 'clamp';
|
|
this.expandable = true;
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.dockTypes.push('unavailable');
|
|
this.dockTypes.push('anyin');
|
|
this.dockTypes.push('in');
|
|
this.dockTypes.push('unavailable');
|
|
this.generator = this.stackClampOneArgBlockGenerator;
|
|
};
|
|
|
|
this.stackClampOneArgBlockGenerator = function (slots) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setCap(true);
|
|
svg.setTail(true);
|
|
svg.setInnies([true]);
|
|
svg.setExpand(10 + this.extraWidth, 0, 0, 0);
|
|
if (slots) {
|
|
svg.setClampSlots(0, slots);
|
|
} else {
|
|
svg.setClampSlots(0, 1);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicClamp();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., mouse button.
|
|
this.booleanZeroArgBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 1;
|
|
this.args = 0;
|
|
this.dockTypes.push('booleanout');
|
|
this.generator = this.booleanZeroArgBlockGenerator;
|
|
};
|
|
|
|
this.booleanZeroArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setExpand(60 + this.extraWidth, 0, 0, 4);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.booleanNot(true);
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., named sensor blocks
|
|
this.booleanOneArgBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 2;
|
|
this.args = 1;
|
|
this.parameter = true;
|
|
this.dockTypes.push('booleanout');
|
|
this.dockTypes.push('textin');
|
|
this.generator = this.booleanOneArgBlockGenerator;
|
|
};
|
|
|
|
this.booleanOneArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
svg.setInnies([true]);
|
|
var artwork = svg.booleanNot(true); // OneArg
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., not
|
|
this.booleanOneBooleanArgBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 2;
|
|
this.args = 1;
|
|
this.parameter = true;
|
|
this.dockTypes.push('booleanout');
|
|
this.dockTypes.push('booleanin');
|
|
this.generator = this.booleanOneBooleanArgBlockGenerator;
|
|
};
|
|
|
|
this.booleanOneBooleanArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.booleanNot(false);
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., and, or
|
|
this.booleanTwoBooleanArgBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 3;
|
|
this.args = 2;
|
|
this.parameter = true;
|
|
this.dockTypes.push('booleanout');
|
|
this.dockTypes.push('booleanin');
|
|
this.dockTypes.push('booleanin');
|
|
this.generator = this.booleanTwoBooleanArgBlockGenerator;
|
|
};
|
|
|
|
this.booleanTwoBooleanArgBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
svg.setExpand(20 + this.extraWidth, 0, 0, 0);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.booleanAndOr();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., greater, less, equal
|
|
this.booleanTwoArgBlock = function () {
|
|
this.style = 'arg';
|
|
this.size = 2;
|
|
this.args = 2;
|
|
this.parameter = true;
|
|
this.expandable = true;
|
|
this.dockTypes.push('booleanout');
|
|
this.dockTypes.push('numberin');
|
|
this.dockTypes.push('numberin');
|
|
this.generator = this.booleanTwoArgBlockGenerator;
|
|
};
|
|
|
|
this.booleanTwoArgBlockGenerator = function (expandY) {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
if (expandY) {
|
|
svg.setExpand(10 + this.extraWidth, (expandY - 1) * STANDARDBLOCKHEIGHT / 2, 0, 0);
|
|
} else {
|
|
svg.setExpand(10 + this.extraWidth, 0, 0, 0);
|
|
}
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.booleanCompare();
|
|
return [artwork, svg.docks];
|
|
};
|
|
|
|
// E.g., color, shade, pensize, ...
|
|
this.parameterBlock = function () {
|
|
this.style = 'arg';
|
|
this.parameter = true;
|
|
this.size = 1;
|
|
this.args = 0;
|
|
this.dockTypes.push('numberout');
|
|
this.generator = this.parameterBlockGenerator;
|
|
};
|
|
|
|
this.parameterBlockGenerator = function () {
|
|
var svg = new SVG();
|
|
svg.init();
|
|
svg.setScale(this.scale);
|
|
// Extra room for parameter label
|
|
svg.setExpand(70 + this.extraWidth, 0, 0, 0);
|
|
svg.setOutie(true);
|
|
if (this.fontsize) {
|
|
svg.setFontSize(this.fontsize);
|
|
}
|
|
var artwork = svg.basicBox();
|
|
return [artwork, svg.docks];
|
|
};
|
|
};
|