// Copyright (c) 2015,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
|
|
|
|
// Borrowing loosely from tasprite_factory.py in the Python version.
|
|
|
|
|
|
function SVG() {
|
|
|
|
// Interface to the graphical representation of blocks, turtles,
|
|
// palettes, etc. on screen.
|
|
// Terms used here:
|
|
// docks -- list of connection points of a block to other blocks
|
|
// innies -- right hand side docks of a block, argument slots
|
|
// outie -- left hand side dock of a block
|
|
// slot -- top dock of a block that can be attached to other blocks
|
|
// cap -- top dock of a block that cannot be attached to other blocks
|
|
// tab -- bottom dock of a block if other blocks can be attached
|
|
// tail -- bottom dock of a block if no other blocks can be attached
|
|
// arm -- connection point of a branching block (if-then, loops) where
|
|
// inner blocks are attached
|
|
// else -- optional second `arm' for if-then-else blocks
|
|
|
|
this.init = function() {
|
|
this._x = 0;
|
|
this._y = 0;
|
|
this._minX = 10000;
|
|
this._minY = 10000;
|
|
this._maxX = -10000;
|
|
this._maxY = -10000;
|
|
this._width = 0;
|
|
this._height = 0;
|
|
this.docks = [];
|
|
this._scale = 1;
|
|
this._orientation = 0;
|
|
this._radius = 8;
|
|
this._strokeWidth = 1;
|
|
this._innies = [];
|
|
this._outie = false;
|
|
this._innieX1 = (9 - this._strokeWidth) / 2;
|
|
this._innieY1 = 3;
|
|
this._innieX2 = (9 - this._strokeWidth) / 2;
|
|
this._innieY2 = (9 - this._strokeWidth) / 2;
|
|
this._inniesSpacer = 9;
|
|
this._padding = this._innieY1 + this._strokeWidth;
|
|
this._slot = true;
|
|
this._cap = false;
|
|
this._tab = true;
|
|
this._bool = false;
|
|
this._slotX = 10;
|
|
this._slotY = 2;
|
|
this._tail = false;
|
|
this._porch = false;
|
|
this._porchX = this._innieX1 + this._innieX2 + 4 * this._strokeWidth;
|
|
this._porchY = this._innieY2;
|
|
this._expandX = 30;
|
|
this._expandX2 = 0;
|
|
this._expandY = 0;
|
|
this._expandY2 = 0;
|
|
this._clampCount = 1;
|
|
this._clampSlots = [1];
|
|
this._slotSize = 21; // TODO: Compute this.
|
|
this._arm = true;
|
|
this._else = false;
|
|
this._draw_inniess = true;
|
|
this._fill = 'fill_color';
|
|
this._stroke = 'stroke_color';
|
|
this.margins = [0, 0, 0, 0];
|
|
this._fontSize = 10;
|
|
}
|
|
|
|
// Attribute methods
|
|
|
|
this.setFontSize = function (fontSize) {
|
|
this._fontSize = fontSize;
|
|
};
|
|
|
|
this.setDrawInniess = function (flag) {
|
|
this._draw_inniess = flag;
|
|
};
|
|
|
|
this.getWidth = function () {
|
|
return this._width;
|
|
};
|
|
|
|
this.getHeight = function () {
|
|
return this._height;
|
|
};
|
|
|
|
this.clearDocks = function () {
|
|
this.docks = [];
|
|
};
|
|
|
|
this.setScale = function (scale) {
|
|
this._scale = scale;
|
|
};
|
|
|
|
this.setOrientation = function (orientation) {
|
|
this._orientation = orientation;
|
|
};
|
|
|
|
this.setClampCount = function (number) {
|
|
this._clampCount = number;
|
|
var n = this._clampSlots.length;
|
|
if (n < number) {
|
|
for (var i = 0; i < number - n; i++) {
|
|
this._clampSlots.push(1);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.setClampSlots = function (clamp, number) {
|
|
if (clamp > this._clampCount.length - 1) {
|
|
this.setClampCount(clamp + 1);
|
|
}
|
|
this._clampSlots[clamp] = number;
|
|
};
|
|
|
|
this.setExpand = function (w, h, w2, h2) {
|
|
// TODO: make this an array
|
|
this._expandX = w;
|
|
this._expandY = h;
|
|
this._expandX2 = w2;
|
|
this._expandY2 = h2;
|
|
};
|
|
|
|
this.setstrokeWidth = function (stroke_width) {
|
|
this._strokeWidth = stroke_width;
|
|
this._calc_porch_params();
|
|
};
|
|
|
|
this.setColors = function (colors) {
|
|
this._fill = colors[0];
|
|
this._stroke = colors[1];
|
|
};
|
|
|
|
this.setFillColor = function (color) {
|
|
this._fill = color;
|
|
};
|
|
|
|
this.setStrokeColor = function (color) {
|
|
this._stroke = color;
|
|
};
|
|
|
|
this.setInnies = function (inniesArray) {
|
|
for (var i = 0; i < inniesArray.length; i++) {
|
|
this._innies.push(inniesArray[i]);
|
|
}
|
|
};
|
|
|
|
this.setOutie = function (flag) {
|
|
// Only one outie.
|
|
this._outie = flag;
|
|
};
|
|
|
|
this.setSlot = function (flag) {
|
|
this._slot = flag;
|
|
if (flag) {
|
|
this._cap = false;
|
|
}
|
|
};
|
|
|
|
this.setCap = function (flag) {
|
|
this._cap = flag;
|
|
if (flag) {
|
|
this._slot = false;
|
|
}
|
|
};
|
|
|
|
this.setTab = function (flag) {
|
|
this._tab = flag;
|
|
if (flag) {
|
|
this._tail = false;
|
|
}
|
|
};
|
|
|
|
this.setTail = function (flag) {
|
|
this._tail = flag;
|
|
if (flag) {
|
|
this._tab = false;
|
|
}
|
|
};
|
|
|
|
this.setPorch = function (flag) {
|
|
this._porch = flag;
|
|
};
|
|
|
|
this.setBoolean = function (flag) {
|
|
this._bool = flag;
|
|
};
|
|
|
|
this.setElse = function (flag) {
|
|
this._else = flag;
|
|
};
|
|
|
|
this.setArm = function (flag) {
|
|
this._arm = flag;
|
|
};
|
|
|
|
// SVG-related helper methods
|
|
|
|
this._resetMinMax = function () {
|
|
this._minX = 10000;
|
|
this._minY = 10000;
|
|
this._maxX = -10000;
|
|
this._maxY = -10000;
|
|
};
|
|
|
|
this._checkMinMax = function () {
|
|
if (this._x < this._minX) {
|
|
this._minX = this._x;
|
|
}
|
|
if (this._y < this._minY) {
|
|
this._minY = this._y;
|
|
}
|
|
if (this._x > this._maxX) {
|
|
this._maxX = this._x;
|
|
}
|
|
if (this._y > this._maxY) {
|
|
this._maxY = this._y;
|
|
}
|
|
};
|
|
|
|
this._calculateXY = function () {
|
|
var x = this._strokeWidth / 2.0;
|
|
var y = this._strokeWidth / 2.0 + this._radius;
|
|
this.margins[0] = x + this._strokeWidth + 0.5;
|
|
this.margins[1] = this._strokeWidth + 0.5;
|
|
if (this._outie) {
|
|
x += this._innieX1 + this._innieX2;
|
|
this.margins[0] += this._innieX1 + this._innieX2;
|
|
}
|
|
if (this._cap) {
|
|
y += this._slotY * 3.0;
|
|
this.margins[1] += this._slotY * 3.0;
|
|
} else if (this._slot) {
|
|
this.margins[1] += this._slotY;
|
|
}
|
|
this.margins[0] *= this._scale;
|
|
this.margins[1] *= this._scale;
|
|
return([x, y]);
|
|
};
|
|
|
|
this._calculateWH = function (addstrokeWidth) {
|
|
if (addstrokeWidth) {
|
|
this._width = (this._maxX - this._minX + this._strokeWidth) * this._scale;
|
|
} else {
|
|
this._width = (this._maxX - this._minX) * this._scale;
|
|
}
|
|
if (this.margins[2] === 0) {
|
|
this.margins[2] = (this._strokeWidth + 0.5) * this._scale;
|
|
} else {
|
|
this.margins[2] = this._width - this.margins[2];
|
|
}
|
|
|
|
if (addstrokeWidth) {
|
|
this._height = (this._maxY - this._minY + this._strokeWidth) * this._scale;
|
|
} else {
|
|
this._height = (this._maxY - this._minY) * this._scale;
|
|
}
|
|
if (this.margins[3] === 0) {
|
|
if (this._tab) {
|
|
this.margins[3] = (this._slotY + this._strokeWidth + 0.5) * this._scale;
|
|
} else {
|
|
this.margins[3] = (this._slotY * 2 + this._strokeWidth + 0.5) * this._scale;
|
|
}
|
|
} else {
|
|
this.margins[3] = this._height - this.margins[3];
|
|
}
|
|
};
|
|
|
|
this._newPath = function (x, y) {
|
|
this._x = x;
|
|
this._y = y;
|
|
return '<path d="m' + x + ' ' + y + ' ';
|
|
};
|
|
|
|
this._closePath = function () {
|
|
return 'z" ';
|
|
};
|
|
|
|
this.text = function (x, y, fontSize, width, alignment, string) {
|
|
this._x = x;
|
|
this._y = y;
|
|
this._checkMinMax();
|
|
this._x = x + width;
|
|
this._y = y - fontSize;
|
|
this._checkMinMax();
|
|
|
|
// writing-mode:lr';
|
|
switch (alignment) {
|
|
case 'left':
|
|
case 'start':
|
|
var align = 'start';
|
|
break;
|
|
case 'middle':
|
|
case 'center':
|
|
var align = 'middle';
|
|
break;
|
|
case 'right':
|
|
case 'end':
|
|
var align = 'end';
|
|
break;
|
|
}
|
|
|
|
var yy = y;
|
|
var tspans = string.split('\n');
|
|
var text = '<text style="font-size:' + fontSize + 'px;fill:#000000;font-family:sans-serif;text-anchor:' + align + '">';
|
|
for (var i = 0; i < tspans.length; i++) {
|
|
text += '<tspan x="' + x + '" y="' + yy + '">' + tspans[i] + '</tspan>';
|
|
yy += fontSize;
|
|
}
|
|
text += '</text>';
|
|
return text;
|
|
};
|
|
|
|
this._lineTo = function (x, y) {
|
|
this._checkMinMax();
|
|
if (this._x === x && this._y === y) {
|
|
return '';
|
|
} else {
|
|
this._x = x;
|
|
this._y = y;
|
|
this._checkMinMax();
|
|
return 'L ' + x + ' ' + y + ' ';
|
|
}
|
|
};
|
|
|
|
this._rLineTo = function (dx, dy) {
|
|
if (dx === 0 && dy === 0) {
|
|
return '';
|
|
} else {
|
|
return this._lineTo(this._x + dx, this._y + dy);
|
|
}
|
|
};
|
|
|
|
this._arcTo = function (x, y, r, a, l, s) {
|
|
this._checkMinMax();
|
|
if (r === 0) {
|
|
return this._lineTo(x, y);
|
|
} else {
|
|
this._x = x;
|
|
this._y = y;
|
|
this._checkMinMax();
|
|
return 'A ' + r + ' ' + r + ' ' + a + ' ' + l + ' ' + s + ' ' + x + ' ' + y + ' ';
|
|
}
|
|
};
|
|
|
|
this._rarcTo = function (signX, signY, a, l, s) {
|
|
if (this._radius === 0) {
|
|
return '';
|
|
} else {
|
|
var x = this._x + signX * this._radius;
|
|
var y = this._y + signY * this._radius;
|
|
return this._arcTo(x, y, this._radius, a, l, s);
|
|
}
|
|
};
|
|
|
|
this._corner = function (signX, signY, a, l, s, start, end, skip) {
|
|
var svg_str = '';
|
|
if (this._radius > 0) {
|
|
var r2 = this._radius / 2.0;
|
|
if (start) {
|
|
if (signX * signY === 1) {
|
|
svg_str += this._rLineTo(signX * r2, 0);
|
|
} else if (!skip) {
|
|
svg_str += this._rLineTo(0, signY * r2);
|
|
}
|
|
}
|
|
var x = this._x + signX * r2;
|
|
var y = this._y + signY * r2;
|
|
svg_str += this._arcTo(x, y, r2, a, l, s);
|
|
if (end) {
|
|
if (signX * signY === 1) {
|
|
svg_str += this._rLineTo(0, signY * r2);
|
|
} else if (!skip) {
|
|
svg_str += this._rLineTo(signX * r2, 0);
|
|
}
|
|
}
|
|
}
|
|
return svg_str;
|
|
};
|
|
|
|
this._iCorner = function (signX, signY, a, l, s, start, end) {
|
|
var r2 = this._strokeWidth + this._radius / 2.0;
|
|
if (start) {
|
|
if (signX * signY === -1) {
|
|
var svg_str = this._rLineTo(signX * (r2 - this._strokeWidth), 0);
|
|
} else {
|
|
var svg_str = this._rLineTo(0, signY * (r2 - this._strokeWidth));
|
|
}
|
|
} else {
|
|
var svg_str = '';
|
|
}
|
|
var x = this._x + signX * r2;
|
|
var y = this._y + signY * r2;
|
|
svg_str += this._arcTo(x, y, r2, a, l, s);
|
|
if (end) {
|
|
if (signX * signY === -1) {
|
|
svg_str += this._rLineTo(0, signY * (r2 - this._strokeWidth));
|
|
} else {
|
|
svg_str += this._rLineTo(signX * (r2 - this._strokeWidth), 0);
|
|
}
|
|
}
|
|
return svg_str;
|
|
};
|
|
|
|
this._doInnie = function () {
|
|
this.docks.push([(this._x + this._strokeWidth) * this._scale,
|
|
(this._y + this._innieY2) * this._scale]);
|
|
if (this.margins[2] === 0) {
|
|
this.margins[1] = (this._y - this._innieY1) * this._scale;
|
|
this.margins[2] = (this._x - this._innieX1 - this._innieX2 - this._strokeWidth * 2) * this._scale;
|
|
}
|
|
this.margins[3] = (this._y + this._innieY2 + this._innieY1) * this._scale;
|
|
return this._rLineTo(-this._innieX1, 0) + this._rLineTo(0, -this._innieY1) + this._rLineTo(-this._innieX2, 0) + this._rLineTo(0, this._innieY2 + 2 * this._innieY1) + this._rLineTo(this._innieX2, 0) + this._rLineTo(0, -this._innieY1) + this._rLineTo(this._innieX1, 0);
|
|
};
|
|
|
|
this._doOutie = function () {
|
|
if (!this._outie) {
|
|
return this._rLineTo(0, -this._innieY2);
|
|
}
|
|
// Outie needs to be the first dock element.
|
|
this.docks.unshift([(this._x * this._scale), (this._y * this._scale)]);
|
|
return this._rLineTo(0, -this._strokeWidth) + this._rLineTo(-this._innieX1 - 2 * this._strokeWidth, 0) + this._rLineTo(0, this._innieY1) + this._rLineTo(-this._innieX2 + 2 * this._strokeWidth, 0) + this._rLineTo(0, -this._innieY2 - 2 * this._innieY1 + 2 * this._strokeWidth) + this._rLineTo(this._innieX2 - 2 * this._strokeWidth, 0) + this._rLineTo(0, this._innieY1) + this._rLineTo(this._innieX1 + 2 * this._strokeWidth, 0) + this._rLineTo(0, -this._strokeWidth);
|
|
};
|
|
|
|
this._doSlot = function () {
|
|
if (this._slot) {
|
|
var x = this._x + this._slotX / 2.0;
|
|
this.docks.push([(x * this._scale), (this._y * this._scale)]);
|
|
return this._rLineTo(0, this._slotY) + this._rLineTo(this._slotX, 0) + this._rLineTo(0, -this._slotY);
|
|
} else if (this._cap) {
|
|
var x = this._x + this._slotX / 2.0;
|
|
this.docks.push([(x * this._scale), (this._y * this._scale)]);
|
|
return this._rLineTo(this._slotX / 2.0, -this._slotY * 3.0) + this._rLineTo(this._slotX / 2.0, this._slotY * 3.0);
|
|
} else {
|
|
return this._rLineTo(this._slotX, 0);
|
|
}
|
|
};
|
|
|
|
this._doTail = function () {
|
|
if (this._outie) {
|
|
return this._rLineTo(-this._slotX, 0);
|
|
} else if (this._tail) {
|
|
var x = this._x + this._slotX / 2.0;
|
|
this.docks.push([(x * this._scale),
|
|
(this._y * this._scale)]);
|
|
return this._rLineTo(-this._slotX / 2.0, this._slotY * 3.0) + this._rLineTo(-this._slotX / 2.0, -this._slotY * 3.0);
|
|
} else {
|
|
return this._rLineTo(-this._slotX, 0);
|
|
}
|
|
};
|
|
|
|
this._doTab = function () {
|
|
if (this._outie) {
|
|
return this._rLineTo(-this._slotX, 0);
|
|
}
|
|
var x = this._x - this._slotX / 2.0;
|
|
this.docks.push([x * this._scale, (this._y + this._strokeWidth) * this._scale]);
|
|
return this._rLineTo(-this._strokeWidth, 0) + this._rLineTo(0, this._slotY) + this._rLineTo(-this._slotX + 2 * this._strokeWidth, 0) + this._rLineTo(0, -this._slotY) + this._rLineTo(-this._strokeWidth, 0);
|
|
};
|
|
|
|
this._doPorch = function (flag) {
|
|
if (flag) {
|
|
return this._rLineTo(0, this._porchY + this._innieY1) + this._rLineTo(this._porchX - this._radius, 0) + this._corner(1, 1, 90, 0, 1, true, true, false);
|
|
} else {
|
|
return this._rLineTo(0, this._porchY - this._padding) + this._rLineTo(this._porchX - this._radius, 0) + this._corner(1, 1, 90, 0, 1, true, true, false);
|
|
}
|
|
};
|
|
|
|
this._startBoolean = function (xoffset, yoffset) {
|
|
var svg = this._newPath(xoffset, yoffset); // - this._radius);
|
|
this._radius -= this._strokeWidth;
|
|
this.docks.push([this._x * this._scale, this._y * this._scale]);
|
|
svg += this._rarcTo(1, -1, 90, 0, 1);
|
|
this._radius += this._strokeWidth;
|
|
svg += this._rLineTo(this._strokeWidth, 0);
|
|
svg += this._rLineTo(0, -this._expandY);
|
|
return svg;
|
|
};
|
|
|
|
this._doBoolean = function () {
|
|
this.docks.push([(this._x - this._radius + this._strokeWidth) * this._scale, (this._y + this._radius) * this._scale]);
|
|
this.margins[2] = (this._x - this._radius - this._strokeWidth) * this._scale;
|
|
var svg = this._rarcTo(-1, 1, 90, 0, 0) + this._rarcTo(1, 1, 90, 0, 0);
|
|
return svg;
|
|
};
|
|
|
|
this._endBoolean = function (notnot) {
|
|
if (!notnot) {
|
|
var svg = this._rLineTo(-this._radius * 1.5, 0);
|
|
} else {
|
|
var svg = '';
|
|
}
|
|
svg += this._rLineTo(0, -this._strokeWidth);
|
|
svg += this._rLineTo(-this._strokeWidth, 0);
|
|
this._radius -= this._strokeWidth;
|
|
svg += this._rarcTo(-1, -1, 90, 0, 1);
|
|
this._radius += this._strokeWidth;
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
return svg;
|
|
};
|
|
|
|
this._header = function (center) {
|
|
// FIXME: Why are our calculations off by 2 x strokeWidth?
|
|
var width = this._width + 2 * this._strokeWidth;
|
|
return '<svg xmlns="http://www.w3.org/2000/svg" width="' + width * 1.1 + '" height="' + this._height * 1.3 + '">' + this._transform(center) + '<filter id="dropshadow" height="130%"> \
|
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/> \
|
|
<feOffset dx="2" dy="2" result="offsetblur"/> \
|
|
<feComponentTransfer xmlns="http://www.w3.org/2000/svg"> \
|
|
<feFuncA type="linear" slope="0.2"/> \
|
|
</feComponentTransfer> \
|
|
<feMerge> \
|
|
<feMergeNode/> \
|
|
<feMergeNode in="SourceGraphic"/> \
|
|
</feMerge> \
|
|
</filter>';
|
|
};
|
|
|
|
this._transform = function (center) {
|
|
if (this._orientation !== 0) {
|
|
var w = this._width / 2.0;
|
|
var h = this._height / 2.0;
|
|
var orientation = '<g transform = "rotate(' + this._orientation + ' ' + w + ' ' + h + ')">';
|
|
} else {
|
|
var orientation = '';
|
|
}
|
|
if (center) {
|
|
var x = -this._minX;
|
|
var y = -this._minY;
|
|
return '<g transform="translate(' + x + ', ' + y + ')">';
|
|
} else {
|
|
return '<g transform="scale(' + this._scale + ', ' + this._scale + ')">' + orientation;
|
|
}
|
|
};
|
|
|
|
this._footer = function () {
|
|
if (this._orientation !== 0) {
|
|
return '</g></g></svg>';
|
|
} else {
|
|
return '</g></svg>';
|
|
}
|
|
};
|
|
|
|
this._style = function () {
|
|
return 'style="fill:' + this._fill + ';fill-opacity:1;stroke:' + this._stroke + ';stroke-width:' + this._strokeWidth + ';stroke-linecap:round;stroke-opacity:1;filter:url(#dropshadow);" />';
|
|
};
|
|
|
|
/*
|
|
The block construction methods typically start on the upper-left side
|
|
of a block and proceed clockwise around the block, first constructing
|
|
a corner (1, -1), a slot or hat on along the top, a corner (1, 1),
|
|
right side connectors ("innies"), possibly a "porch" to suggest an
|
|
order of arguments, another corner (-1, 1), a tab or tail, and the
|
|
fourth corner (-1, -1), and finally, a left-side connector ("outie").
|
|
In addition:
|
|
* Minimum and maximum values are calculated for the SVG bounding box;
|
|
* Docking coordinates are calculated for each innies, outie, tab, and slot.
|
|
*/
|
|
|
|
this.basicBlock = function() {
|
|
// The most common block type: used for 0, 1, 2, or 3
|
|
// argument commands (forward, setxy, plus, sqrt, etc.)
|
|
this._resetMinMax();
|
|
|
|
var obj = this._calculateXY();
|
|
var x = obj[0];
|
|
var y = obj[1];
|
|
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
|
|
var svg = this._newPath(x, y);
|
|
svg += this._corner(1, -1 , 90, 0, 1, true, true, false);
|
|
svg += this._doSlot();
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
xx = this._x;
|
|
svg += this._corner(1, 1 , 90, 0, 1, true, true, false);
|
|
if (this._innies.length === 0) {
|
|
// To maintain standard block height
|
|
svg += this._rLineTo(0, this._padding);
|
|
} else {
|
|
for (var i = 0; i < this._innies.length; i++) {
|
|
if (this._innies[i]) {
|
|
svg += this._doInnie();
|
|
}
|
|
if (i === 0) {
|
|
svg += this._rLineTo(0, this._expandY);
|
|
} else if (i === 1 && this._expandY2 > 0) {
|
|
svg += this._rLineTo(0, this._expandY2);
|
|
}
|
|
if (i === 0 && this._porch) {
|
|
svg += this._doPorch(false);
|
|
} else if (this._innies.length - 1 > i) {
|
|
svg += this._rLineTo(0, 2 * this._innieY2 + this._inniesSpacer);
|
|
}
|
|
}
|
|
}
|
|
svg += this._corner(-1, 1 , 90, 0, 1, true, true, false);
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
if (this._tab) {
|
|
svg += this._doTab();
|
|
} else {
|
|
svg += this._doTail();
|
|
}
|
|
svg += this._corner(-1, -1 , 90, 0, 1, true, true, false);
|
|
svg += this._rLineTo(0, -this._expandY);
|
|
if (this._innies.indexOf(true) !== -1) {
|
|
svg += this._lineTo(x, this._radius + this._innieY2 + this._strokeWidth / 2.0);
|
|
svg += this._doOutie();
|
|
}
|
|
|
|
this._calculateWH(true);
|
|
svg += this._closePath();
|
|
svg += this._style();
|
|
|
|
// Add a block label
|
|
var tx = this._width - this._scale * (this._innieX1 + this._innieX2) - 4 * this._strokeWidth;
|
|
var ty = this._height / 2 + this._fontSize / (5 / this._scale);
|
|
|
|
// If we have an odd number of innie slots, we need to avoid a
|
|
// collision between the block label and the slot label.
|
|
var nInnies = this._innies.length;
|
|
if (nInnies > 2 && Math.round(nInnies / 2) * 2 !== nInnies) {
|
|
ty -= 2 * this._fontSize;
|
|
}
|
|
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'right', 'block_label');
|
|
|
|
// Add a label for each innies
|
|
if (this._slot || this._outie) {
|
|
var di = 1; // Skip the first dock since it is a slot.
|
|
} else {
|
|
var di = 0;
|
|
}
|
|
var count = 1;
|
|
for (var i = 0; i < this._innies.length; i++) {
|
|
if (this._innies[i]) {
|
|
ty = this.docks[di][1] - (this._fontSize / (8 / this._scale));
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize / 1.5, this._width, 'right', 'arg_label_' + count);
|
|
count += 1;
|
|
di += 1;
|
|
}
|
|
}
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.basicBox = function () {
|
|
// Basic argument style used for numbers, text, media, parameters
|
|
this._resetMinMax();
|
|
this.setOutie(true);
|
|
|
|
var x = this._strokeWidth / 2.0 + this._innieX1 + this._innieX2;
|
|
this.margins[0] = (x + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[1] = (this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
var svg = this._newPath(x, this._strokeWidth / 2.0);
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
svg += this._rLineTo(0, 2 * this._radius + this._innieY2 + this._expandY);
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
svg += this._lineTo(x, this._radius + this._innieY2 + this._strokeWidth / 2.0);
|
|
svg += this._doOutie();
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
|
|
// Add a block label
|
|
var tx = 2 * (this._innieX1 + this._innieX2) + 4 * this._strokeWidth;
|
|
var ty = this._height / 2 + this._fontSize / 2;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'left', 'block_label');
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.booleanAndOr = function () {
|
|
// Booleans are in a class of their own
|
|
this._resetMinMax();
|
|
var svg = this._startBoolean(this._strokeWidth / 2.0, this._radius * 5.5 + this._strokeWidth / 2.0 + this._innieY2 + this._inniesSpacer + this._expandY);
|
|
svg += this._rLineTo(0, -this._radius * 3.5 - this._innieY2 - this._inniesSpacer - this._strokeWidth);
|
|
|
|
svg += this._rarcTo(1, -1, 90, 0, 1);
|
|
svg += this._rLineTo(this._radius / 2.0 + this._expandX, 0);
|
|
var xx = this._x;
|
|
svg += this._rLineTo(0, this._radius / 2.0);
|
|
svg += this._doBoolean();
|
|
svg += this._rLineTo(0, this._radius * 1.5 + this._innieY2 + this._inniesSpacer);
|
|
|
|
svg += this._rLineTo(0, this._expandY);
|
|
|
|
svg += this._doBoolean();
|
|
svg += this._rLineTo(0, this._radius / 2.0);
|
|
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
svg += this._endBoolean(false);
|
|
this.margins[0] = (this._radius + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[1] = this._strokeWidth * this._scale;
|
|
this.margins[2] = this._strokeWidth * this._scale;
|
|
this.margins[3] = this._strokeWidth * this._scale;
|
|
|
|
// Add a block label
|
|
var tx = this._width - this._scale * (this._innieX1 + this._innieX2) - 4 * this._strokeWidth;
|
|
var ty = this._height / 2 + this._fontSize / 2;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'right', 'block_label');
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.booleanNot = function (notnot) {
|
|
// Booleans are in a class of their own: not and not not
|
|
this._resetMinMax();
|
|
if (this._innies[0]) {
|
|
var svg = this._startBoolean(this._strokeWidth / 2.0, this._radius * 1.25 + this._strokeWidth / 2.0);
|
|
} else if (!notnot) {
|
|
var svg = this._startBoolean(this._strokeWidth / 2.0, this._radius * 2.0 + this._strokeWidth / 2.0);
|
|
} else {
|
|
var svg = this._startBoolean(this._strokeWidth / 2.0, this._radius * 1.25 + this._strokeWidth / 2.0);
|
|
}
|
|
svg += this._rLineTo(0, -this._strokeWidth);
|
|
|
|
if (this._innies[0]) {
|
|
svg += this._rLineTo(0, -this._radius / 4.0);
|
|
} else if (!notnot) {
|
|
svg += this._rarcTo(1, -1, 90, 0, 1);
|
|
} else {
|
|
svg += this._rLineTo(0, -this._radius / 4.0);
|
|
}
|
|
svg += this._rLineTo(this._radius / 2.0 + this._expandX, 0);
|
|
var xx = this._x;
|
|
|
|
if (this._innies[0]) {
|
|
svg += this._rLineTo(0, this._radius);
|
|
svg += this._doInnie();
|
|
svg += this._rLineTo(0, this._radius);
|
|
} else if (!notnot) {
|
|
svg += this._rLineTo(0, this._radius / 2.0);
|
|
svg += this._doBoolean();
|
|
svg += this._rLineTo(0, this._radius / 2.0);
|
|
} else {
|
|
svg += this._rLineTo(0, this._radius * 2.25);
|
|
}
|
|
|
|
svg += this._lineTo(xx, this._y);
|
|
|
|
// FIXME: Is this in the correct place?
|
|
if (this._expandY2 > 0) {
|
|
svg += this._rLineTo(0, this._expandY2);
|
|
}
|
|
|
|
if (this._innies[0]) {
|
|
svg += this._rLineTo(-this._radius / 2.0 - this._expandX, 0);
|
|
svg += this._rLineTo(0, -this._radius / 4.0);
|
|
} else if (!notnot) {
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
} else {
|
|
svg += this._rLineTo(-this._radius / 2.0 - this._expandX, 0);
|
|
}
|
|
|
|
// FIXME: Is this in the correct place?
|
|
if (this._expandY2 > 0) {
|
|
svg += this._rLineTo(0, -this._expandY2);
|
|
}
|
|
svg += this._endBoolean(notnot);
|
|
if (notnot) {
|
|
this.margins[0] = (this._radius + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = (this._radius + this._strokeWidth + 0.5) * this._scale;
|
|
} else {
|
|
this.margins[0] = (this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = (this._strokeWidth + 0.5) * this._scale;
|
|
}
|
|
this.margins[1] = this._strokeWidth * this._scale;
|
|
this.margins[3] = this._strokeWidth * this._scale;
|
|
|
|
// Add a block label
|
|
var tx = this._width - 2 * (this._innieX1 + this._innieX2) - 4 * this._strokeWidth;
|
|
var ty = this._height / 2 + this._fontSize / 2;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'right', 'block_label');
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.booleanCompare = function () {
|
|
// Booleans are in a class of their own (greater than, less than, etc)
|
|
this._resetMinMax();
|
|
var yoffset = this._radius * 2 + 2 * this._innieY2 + this._inniesSpacer + this._strokeWidth / 2.0 + this._expandY;
|
|
var xoffset = this._strokeWidth / 2.0;
|
|
|
|
var yoff = this._radius * 2;
|
|
var svg = '<g transform="matrix(1,0,0,1,0,-' + yoff + ')"> ';
|
|
|
|
svg += this._newPath(xoffset, yoffset + this._radius);
|
|
this.docks.push([this._x * this._scale, (this._y - 2 * this._radius) * this._scale]);
|
|
this._radius -= this._strokeWidth;
|
|
svg += this._rarcTo(1, -1, 90, 0, 1);
|
|
this._radius += this._strokeWidth;
|
|
svg += this._rLineTo(this._strokeWidth, 0);
|
|
svg += this._rLineTo(0, -this._expandY);
|
|
|
|
yoffset = -2 * this._innieY2 - this._inniesSpacer - this._strokeWidth;
|
|
svg += this._rLineTo(0, yoffset + this._radius);
|
|
|
|
svg += this._rarcTo(1, -1, 90, 0, 1);
|
|
svg += this._rLineTo(this._radius / 2.0 + this._expandX, 0);
|
|
svg += this._rLineTo(0, this._radius);
|
|
var xx = this._x;
|
|
svg += this._doInnie();
|
|
this.docks[1][1] -= this._radius * 2 * this._scale;
|
|
svg += this._rLineTo(0, this._expandY);
|
|
|
|
if (this._porch) {
|
|
svg += this._doPorch(false);
|
|
} else {
|
|
svg += this._rLineTo(0, 2 * this._innieY2 + this._inniesSpacer);
|
|
}
|
|
svg += this._doInnie();
|
|
this.docks[2][1] -= this._radius * 2 * this._scale;
|
|
svg += this._rLineTo(0, this._radius);
|
|
svg += this._lineTo(xx, this._y);
|
|
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
|
|
svg += this._rLineTo(-this._radius * 1.5, 0);
|
|
svg += this._rLineTo(0, -this._radius);
|
|
svg += this._rLineTo(0, -this._strokeWidth);
|
|
svg += this._rLineTo(-this._strokeWidth, 0);
|
|
this._radius -= this._strokeWidth;
|
|
svg += this._rarcTo(-1, -1, 90, 0, 1);
|
|
this._radius += this._strokeWidth;
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
svg += '</g>';
|
|
|
|
this.margins[0] = (this._radius + this._strokeWidth) * this._scale;
|
|
this.margins[1] = this._strokeWidth * this._scale;
|
|
this.margins[2] = this._strokeWidth * this._scale;
|
|
|
|
// Add a block label
|
|
var tx = this._width - 2 * (this._innieX1 + this._innieX2) - 4 * this._strokeWidth;
|
|
var ty = this._height / 2 + this._fontSize / 2; // + this._radius * this._scale;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'right', 'block_label');
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.basicClamp = function () {
|
|
// Special block for collapsible stacks; includes an 'arm'
|
|
// that extends down the left side of a stack and a bottom jaw
|
|
// to clamp the blocks. (Used for start, action, repeat, etc.)
|
|
var save_cap = this._cap;
|
|
var save_slot = this._slot;
|
|
this._resetMinMax();
|
|
if (this._outie) {
|
|
var x = this._strokeWidth / 2.0 + this._innieX1 + this._innieX2;
|
|
} else {
|
|
var x = this._strokeWidth / 2.0;
|
|
}
|
|
if (this._cap) {
|
|
var y = this._strokeWidth / 2.0 + this._radius + this._slotY * 3.0;
|
|
} else {
|
|
var y = this._strokeWidth / 2.0 + this._radius;
|
|
}
|
|
|
|
this.margins[0] = (x + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[1] = (this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
|
|
var svg = this._newPath(x, y);
|
|
svg += this._corner(1, -1 , 90, 0, 1, true, true, false);
|
|
svg += this._doSlot();
|
|
if (this._cap) {
|
|
this._slot = true;
|
|
this._cap = false;
|
|
}
|
|
|
|
svg += this._rLineTo(this._radius + this._strokeWidth, 0);
|
|
var xx = this._x;
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
svg += this._corner(1, 1 , 90, 0, 1, true, true, false);
|
|
if (this._innies[0]) {
|
|
// svg += this._doInnie();
|
|
for (var i = 0; i < this._innies.length; i++) {
|
|
if (this._innies[i]) {
|
|
svg += this._doInnie();
|
|
}
|
|
if (i === 0) {
|
|
svg += this._rLineTo(0, this._expandY);
|
|
} else if (i === 1 && this._expandY2 > 0) {
|
|
svg += this._rLineTo(0, this._expandY2);
|
|
}
|
|
if (i === 0 && this._porch) {
|
|
svg += this._doPorch(false);
|
|
} else if (this._innies.length - 1 > i) {
|
|
svg += this._rLineTo(0, 2 * this._innieY2 + this._inniesSpacer);
|
|
}
|
|
}
|
|
} else if (this._bool) {
|
|
svg += this._rLineTo(0, 2 * this._padding + this._strokeWidth);
|
|
svg += this._doBoolean();
|
|
this.margins[2] = (this._x - this._strokeWidth + 0.5) * this._scale;
|
|
} else {
|
|
svg += this._rLineTo(0, this._padding);
|
|
this.margins[2] = (this._x - this._strokeWidth + 0.5) * this._scale;
|
|
}
|
|
|
|
for (var clamp = 0; clamp < this._clampCount; clamp++) {
|
|
if (clamp > 0) {
|
|
svg += this._rLineTo(0, 3 * this._padding);
|
|
}
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._lineTo(xx, this._y);
|
|
var saveOutie = this._outie;
|
|
this._outie = false;
|
|
svg += this._doTab();
|
|
this._outie = saveOutie;
|
|
svg += this._iCorner(-1, 1, 90, 0, 0, true, true);
|
|
svg += this._rLineTo(0, this._padding);
|
|
if (this._clampSlots[clamp] > 1) {
|
|
var dy = this._slotSize * (this._clampSlots[clamp] - 1);
|
|
svg += this._rLineTo(0, dy);
|
|
}
|
|
svg += this._rLineTo(0, this._expandY2);
|
|
svg += this._iCorner(1, 1, 90, 0, 0, true, true);
|
|
var saveSlot = this._slot;
|
|
this._slot = true;
|
|
svg += this._doSlot();
|
|
this._slot = saveSlot;
|
|
this.docks.pop(); // We don't need this dock.
|
|
svg += this._rLineTo(this._radius, 0);
|
|
}
|
|
svg += this._rLineTo(0, this._innieY1 * 2);
|
|
|
|
// Add a bit of padding to make multiple of standard block height.
|
|
svg += this._rLineTo(0, this._innieY1 + 3 * this._strokeWidth);
|
|
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
|
|
if (this._clampCount === 0) {
|
|
svg += this._lineTo(xx, this._y);
|
|
}
|
|
|
|
svg += this._rLineTo(-this._radius - this._strokeWidth, 0);
|
|
|
|
if (this._tail) {
|
|
svg += this._doTail();
|
|
} else {
|
|
svg += this._doTab();
|
|
}
|
|
|
|
this._cap = save_cap;
|
|
this._slot = save_slot;
|
|
|
|
svg += this._corner(-1, -1, 90, 0, 1, true, true, false);
|
|
if (this._outie) {
|
|
svg += this._lineTo(x, this._radius + this._innieY2 + this._strokeWidth / 2.0);
|
|
svg += this._doOutie();
|
|
}
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
|
|
// Add a block label
|
|
if (this._outie) {
|
|
var tx = 10 * this._strokeWidth + this._innieX1 + this._innieX2;
|
|
} else {
|
|
var tx = 8 * this._strokeWidth;
|
|
}
|
|
if (this._cap) {
|
|
var ty = (this._strokeWidth / 2.0 + this._radius + this._slotY) * this._scale;
|
|
} else if (this._innies.length > 1) {
|
|
var ty = (this._strokeWidth / 2.0 + this._radius) * this._scale / 2;
|
|
ty += this._fontSize;
|
|
} else {
|
|
var ty = (this._strokeWidth / 2.0 + this._radius) * this._scale / 2;
|
|
}
|
|
ty += (this._fontSize + 1) * this._scale;
|
|
if (this._bool) {
|
|
ty += this._fontSize / 2;
|
|
}
|
|
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'left', 'block_label');
|
|
|
|
// Booleans get an extra label.
|
|
if (this._bool) {
|
|
var count = 1;
|
|
var tx = this._width - this._radius;
|
|
for (var clamp = 0; clamp < this._clampCount; clamp++) {
|
|
ty = this.docks[clamp + 2][1] - this._fontSize + 3 * this._strokeWidth;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize / 1.5, this._width, 'right', 'arg_label_' + count);
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
// Add a label for each innies
|
|
if (this._slot || this._outie) {
|
|
var di = 1; // Skip the first dock since it is a slot.
|
|
} else {
|
|
var di = 0;
|
|
}
|
|
var count = 1;
|
|
var tx = this._width - this._scale * (this._innieX1 + this._innieX2) - 4 * this._strokeWidth;
|
|
for (var i = 0; i < this._innies.length; i++) {
|
|
if (this._innies[i]) {
|
|
ty = this.docks[di][1] - (this._fontSize / (8 / this._scale));
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize / 1.5, this._width, 'right', 'arg_label_' + count);
|
|
count += 1;
|
|
di += 1;
|
|
}
|
|
}
|
|
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.argClamp = function () {
|
|
// A clamp that contains innies rather than flow blocks
|
|
this._resetMinMax();
|
|
if (this._outie) {
|
|
var x = this._strokeWidth / 2.0 + this._innieX1 + this._innieX2;
|
|
} else {
|
|
var x = this._strokeWidth / 2.0;
|
|
}
|
|
var y = this._strokeWidth / 2.0 + this._radius;
|
|
this.margins[0] = (x + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[1] = (this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
var svg = this._newPath(x, y);
|
|
svg += this._corner(1, -1 , 90, 0, 1, true, true, false);
|
|
svg += this._doSlot();
|
|
|
|
svg += this._rLineTo(this._radius + this._strokeWidth, 0);
|
|
var xx = this._x;
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
svg += this._corner(1, 1 , 90, 0, 1, true, true, false);
|
|
if (this._innies[0]) {
|
|
svg += this._doInnie();
|
|
} else {
|
|
svg += this._rLineTo(0, this._padding);
|
|
this.margins[2] = (this._x - this._strokeWidth + 0.5) * this._scale;
|
|
}
|
|
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._iCorner(-1, 1, 90, 0, 0, true, true);
|
|
|
|
var j = 0;
|
|
svg += this._doInnie();
|
|
var dy = this._slotSize * (this._clampSlots[0][j] - 1);
|
|
if (dy > 0) {
|
|
svg += this._rLineTo(0, dy);
|
|
}
|
|
j += 1;
|
|
|
|
var ddy = (this._slotSize - this._innieY2);
|
|
for (var i = 1; i < this._clampSlots[0].length; i++) {
|
|
svg += this._rLineTo(0, ddy);
|
|
svg += this._doInnie();
|
|
var dy = this._slotSize * (this._clampSlots[0][j] - 1);
|
|
if (dy > 0) {
|
|
svg += this._rLineTo(0, dy);
|
|
}
|
|
j += 1;
|
|
}
|
|
|
|
svg += this._rLineTo(0, this._expandY2);
|
|
svg += this._iCorner(1, 1, 90, 0, 0, true, true);
|
|
svg += this._rLineTo(this._radius, 0);
|
|
|
|
svg += this._rLineTo(0, this._innieY1 * 2);
|
|
|
|
// Add a bit of padding to make multiple of standard block height.
|
|
svg += this._rLineTo(0, this._innieY1 + 3 * this._strokeWidth);
|
|
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._rLineTo(-this._radius - this._strokeWidth, 0);
|
|
|
|
if (this._tail) {
|
|
svg += this._doTail();
|
|
} else {
|
|
svg += this._doTab();
|
|
}
|
|
|
|
svg += this._corner(-1, -1, 90, 0, 1, true, true, false);
|
|
if (this._outie) {
|
|
svg += this._lineTo(x, this._radius + this._innieY2 + this._strokeWidth / 2.0);
|
|
svg += this._doOutie();
|
|
}
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
|
|
// Add a block label
|
|
if (this._outie) {
|
|
var tx = 10 * this._strokeWidth + this._innieX1 + this._innieX2;
|
|
} else {
|
|
var tx = 8 * this._strokeWidth;
|
|
}
|
|
if (this._cap) {
|
|
var ty = (this._strokeWidth / 2.0 + this._radius + this._slotY) * this._scale;
|
|
} else {
|
|
var ty = (this._strokeWidth / 2.0 + this._radius) * this._scale / 2;
|
|
}
|
|
ty += (this._fontSize + 1) * this._scale;
|
|
if (this._bool) {
|
|
ty += this._fontSize / 2;
|
|
}
|
|
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'left', 'block_label');
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.untilClamp = function () {
|
|
// Until block is like clamp but docks are flipped
|
|
this._resetMinMax();
|
|
var x = this._strokeWidth / 2.0;
|
|
var y = this._strokeWidth / 2.0 + this._radius;
|
|
this.margins[0] = (x + this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[1] = (this._strokeWidth + 0.5) * this._scale;
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
var svg = this._newPath(x, y);
|
|
svg += this._corner(1, -1, 90, 0, 1, true, true, false);
|
|
svg += this._doSlot();
|
|
svg += this._rLineTo(this._radius + this._strokeWidth, 0);
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
var xx = this._x;
|
|
svg += this._corner(1, 1, 90, 0, 1, true, true, true);
|
|
svg += this._rLineTo(0, 2 * this._innieY1);
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, true);
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
svg += this._doTab();
|
|
svg += this._iCorner(-1, 1, 90, 0, 0, true, true);
|
|
svg += this._rLineTo(0, this._expandY);
|
|
svg += this._iCorner(1, 1, 90, 0, 0, true, true);
|
|
svg += this._doSlot();
|
|
this.docks.pop(); // We don't need this dock.
|
|
svg += this._rLineTo(this._radius, 0);
|
|
if (this._innies[0]) {
|
|
svg += this._doInnie();
|
|
} else {
|
|
this.margins[2] = (this._x - this._strokeWidth + 0.5) * this._scale;
|
|
}
|
|
svg += this._rLineTo(0, this._radius + this._expandY2);
|
|
if (this._bool) {
|
|
svg += this._doBoolean();
|
|
}
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._rLineTo(-this._radius - this._strokeWidth, 0);
|
|
svg += this._doTab();
|
|
svg += this._corner(-1, -1, 90, 0, 1, true, true, false);
|
|
svg += this._closePath();
|
|
this._calculateWH(true);
|
|
svg += this._style();
|
|
|
|
// Add a block label
|
|
var tx = 4 * this._strokeWidth;
|
|
var ty = this.docks[2][1];
|
|
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize, this._width, 'left', 'block_label');
|
|
|
|
if (this._bool) {
|
|
// Booleans get an extra label.
|
|
var tx = this._width - this._radius;
|
|
ty = this.docks[1][1] - this._fontSize;
|
|
svg += this.text(tx / this._scale, ty / this._scale, this._fontSize / 1.5, this._width, 'right', 'arg_label_1');
|
|
}
|
|
|
|
if (this._bool) {
|
|
// Swap bool and tab args so that the docking behaves like the
|
|
// while block.
|
|
var tx = this.docks[1][0];
|
|
var ty = this.docks[1][1];
|
|
this.docks[1][0] = this.docks[2][0];
|
|
this.docks[1][1] = this.docks[2][1];
|
|
this.docks[2][0] = tx;
|
|
this.docks[2][1] = ty;
|
|
}
|
|
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
|
|
this.statusBlock = function (graphic) {
|
|
// Generate a status block
|
|
this._resetMinMax();
|
|
var obj = this._calculateXY();
|
|
var x = obj[0];
|
|
var y = obj[1];
|
|
this.margins[2] = 0;
|
|
this.margins[3] = 0;
|
|
var svg = this._newPath(x, y);
|
|
svg += this._corner(1, -1, 90, 0, 1, true, true, false);
|
|
svg += this._rLineTo(this._expandX, 0);
|
|
var xx = this._x;
|
|
svg += this._corner(1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._rLineTo(0, this._expandY);
|
|
svg += this._corner(-1, 1, 90, 0, 1, true, true, false);
|
|
svg += this._lineTo(xx, this._y);
|
|
svg += this._rLineTo(-this._expandX, 0);
|
|
svg += this._corner(-1, -1, 90, 0, 1, true, true, false);
|
|
svg += this._rLineTo(0, -this._expandY);
|
|
this._calculateWH(true);
|
|
svg += this._closePath();
|
|
svg += this._style();
|
|
svg += this._footer();
|
|
return this._header(false) + svg;
|
|
};
|
|
};
|