refactor: convert renderer classes to es6 classes (#5874)

* refactor: convert zelos renderer classes to es6 classes

* refactor: convert zelos measurables to es6 classes

* refactor: convert thrasos classes to es6 classes

* refactor: convert minimalist classes to es6 classes

* refactor: update geras classes to es6 classes

* chore: rebuild and format

* chore: fix indentation in comments
This commit is contained in:
Rachel Fenichel
2022-01-14 12:43:13 -08:00
committed by GitHub
parent 29fb7b7893
commit f5caf964aa
27 changed files with 3711 additions and 3588 deletions

View File

@@ -114,6 +114,13 @@ const MarkerSvg = function(workspace, constants, marker) {
* @type {string}
*/
this.colour_ = marker.colour || defaultColour;
/**
* The root SVG group containing the marker.
* @type {SVGGElement}
* @protected
*/
this.markerSvg_ = null;
};
/**

View File

@@ -17,57 +17,57 @@
*/
goog.module('Blockly.geras.ConstantProvider');
const object = goog.require('Blockly.utils.object');
const {ConstantProvider: BaseConstantProvider} = goog.require('Blockly.blockRendering.ConstantProvider');
/**
* An object that provides constants for rendering blocks in Geras mode.
* @constructor
* @package
* @extends {BaseConstantProvider}
* @alias Blockly.geras.ConstantProvider
*/
const ConstantProvider = function() {
ConstantProvider.superClass_.constructor.call(this);
class ConstantProvider extends BaseConstantProvider {
/**
* @package
* @alias Blockly.geras.ConstantProvider
*/
constructor() {
super();
/**
* @override
*/
this.FIELD_TEXT_BASELINE_CENTER = false;
// The dark/shadow path in classic rendering is the same as the normal block
// path, but translated down one and right one.
this.DARK_PATH_OFFSET = 1;
/**
* The maximum width of a bottom row that follows a statement input and has
* inputs inline.
* @type {number}
*/
this.MAX_BOTTOM_WIDTH = 30;
/**
* @override
*/
this.STATEMENT_BOTTOM_SPACER = -this.NOTCH_HEIGHT / 2;
}
/**
* @override
*/
this.FIELD_TEXT_BASELINE_CENTER = false;
// The dark/shadow path in classic rendering is the same as the normal block
// path, but translated down one and right one.
this.DARK_PATH_OFFSET = 1;
/**
* The maximum width of a bottom row that follows a statement input and has
* inputs inline.
* @type {number}
*/
this.MAX_BOTTOM_WIDTH = 30;
/**
* @override
*/
this.STATEMENT_BOTTOM_SPACER = -this.NOTCH_HEIGHT / 2;
};
object.inherits(ConstantProvider, BaseConstantProvider);
/**
* @override
*/
ConstantProvider.prototype.getCSS_ = function(selector) {
return ConstantProvider.superClass_.getCSS_.call(this, selector).concat([
/* eslint-disable indent */
// Insertion marker.
selector + ' .blocklyInsertionMarker>.blocklyPathLight,',
selector + ' .blocklyInsertionMarker>.blocklyPathDark {',
'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';', 'stroke: none;',
'}',
/* eslint-enable indent */
]);
};
getCSS_(selector) {
return super.getCSS_(selector).concat([
/* eslint-disable indent */
// Insertion marker.
selector + ' .blocklyInsertionMarker>.blocklyPathLight,',
selector + ' .blocklyInsertionMarker>.blocklyPathDark {',
'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';', 'stroke: none;',
'}',
/* eslint-enable indent */
]);
}
}
exports.ConstantProvider = ConstantProvider;

View File

@@ -16,13 +16,14 @@
goog.module('Blockly.geras.Drawer');
const debug = goog.require('Blockly.blockRendering.debug');
const object = goog.require('Blockly.utils.object');
const svgPaths = goog.require('Blockly.utils.svgPaths');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Drawer: BaseDrawer} = goog.require('Blockly.blockRendering.Drawer');
const {Highlighter} = goog.require('Blockly.geras.Highlighter');
/* eslint-disable-next-line no-unused-vars */
const {InlineInput} = goog.require('Blockly.geras.InlineInput');
/* eslint-disable-next-line no-unused-vars */
const {PathObject} = goog.requireType('Blockly.geras.PathObject');
/* eslint-disable-next-line no-unused-vars */
const {RenderInfo} = goog.requireType('Blockly.geras.RenderInfo');
@@ -30,183 +31,185 @@ const {RenderInfo} = goog.requireType('Blockly.geras.RenderInfo');
/**
* An object that draws a block based on the given rendering information.
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @constructor
* @extends {BaseDrawer}
* @alias Blockly.geras.Drawer
*/
const Drawer = function(block, info) {
Drawer.superClass_.constructor.call(this, block, info);
// Unlike Thrasos, Geras has highlights and drop shadows.
this.highlighter_ = new Highlighter(info);
};
object.inherits(Drawer, BaseDrawer);
/**
* @override
*/
Drawer.prototype.draw = function() {
this.hideHiddenIcons_();
this.drawOutline_();
this.drawInternals_();
const pathObject =
/** @type {!PathObject} */ (this.block_.pathObject);
pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
pathObject.setHighlightPath(this.highlighter_.getPath());
if (this.info_.RTL) {
pathObject.flipRTL();
class Drawer extends BaseDrawer {
/**
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @alias Blockly.geras.Drawer
*/
constructor(block, info) {
super(block, info);
// Unlike Thrasos, Geras has highlights and drop shadows.
this.highlighter_ = new Highlighter(info);
}
if (debug.isDebuggerEnabled()) {
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
}
this.recordSizeOnBlock_();
};
/**
* @override
*/
Drawer.prototype.drawTop_ = function() {
this.highlighter_.drawTopCorner(this.info_.topRow);
this.highlighter_.drawRightSideRow(this.info_.topRow);
/**
* @override
*/
draw() {
this.hideHiddenIcons_();
this.drawOutline_();
this.drawInternals_();
Drawer.superClass_.drawTop_.call(this);
};
/**
* @override
*/
Drawer.prototype.drawJaggedEdge_ = function(row) {
this.highlighter_.drawJaggedEdge_(row);
Drawer.superClass_.drawJaggedEdge_.call(this, row);
};
/**
* @override
*/
Drawer.prototype.drawValueInput_ = function(row) {
this.highlighter_.drawValueInput(row);
Drawer.superClass_.drawValueInput_.call(this, row);
};
/**
* @override
*/
Drawer.prototype.drawStatementInput_ = function(row) {
this.highlighter_.drawStatementInput(row);
Drawer.superClass_.drawStatementInput_.call(this, row);
};
/**
* @override
*/
Drawer.prototype.drawRightSideRow_ = function(row) {
this.highlighter_.drawRightSideRow(row);
this.outlinePath_ += svgPaths.lineOnAxis('H', row.xPos + row.width) +
svgPaths.lineOnAxis('V', row.yPos + row.height);
};
/**
* @override
*/
Drawer.prototype.drawBottom_ = function() {
this.highlighter_.drawBottomRow(this.info_.bottomRow);
Drawer.superClass_.drawBottom_.call(this);
};
/**
* Add steps for the left side of the block, which may include an output
* connection
* @protected
* @override
*/
Drawer.prototype.drawLeft_ = function() {
this.highlighter_.drawLeft();
Drawer.superClass_.drawLeft_.call(this);
};
/**
* @override
*/
Drawer.prototype.drawInlineInput_ = function(input) {
this.highlighter_.drawInlineInput(input);
Drawer.superClass_.drawInlineInput_.call(this, input);
};
/**
* @override
*/
Drawer.prototype.positionInlineInputConnection_ = function(input) {
const yPos = input.centerline - input.height / 2;
// Move the connection.
if (input.connectionModel) {
// xPos already contains info about startX
let connX =
input.xPos + input.connectionWidth + this.constants_.DARK_PATH_OFFSET;
const pathObject =
/** @type {!PathObject} */ (this.block_.pathObject);
pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
pathObject.setHighlightPath(this.highlighter_.getPath());
if (this.info_.RTL) {
connX *= -1;
pathObject.flipRTL();
}
input.connectionModel.setOffsetInBlock(
connX,
yPos + input.connectionOffsetY + this.constants_.DARK_PATH_OFFSET);
}
};
/**
* @override
*/
Drawer.prototype.positionStatementInputConnection_ = function(row) {
const input = row.getLastInput();
if (input.connectionModel) {
let connX = row.xPos + row.statementEdge + input.notchOffset;
if (this.info_.RTL) {
connX *= -1;
} else {
connX += this.constants_.DARK_PATH_OFFSET;
if (debug.isDebuggerEnabled()) {
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
}
input.connectionModel.setOffsetInBlock(
connX, row.yPos + this.constants_.DARK_PATH_OFFSET);
this.recordSizeOnBlock_();
}
};
/**
* @override
*/
Drawer.prototype.positionExternalValueConnection_ = function(row) {
const input = row.getLastInput();
if (input.connectionModel) {
let connX = row.xPos + row.width + this.constants_.DARK_PATH_OFFSET;
if (this.info_.RTL) {
connX *= -1;
/**
* @override
*/
drawTop_() {
this.highlighter_.drawTopCorner(this.info_.topRow);
this.highlighter_.drawRightSideRow(this.info_.topRow);
super.drawTop_();
}
/**
* @override
*/
drawJaggedEdge_(row) {
this.highlighter_.drawJaggedEdge_(row);
super.drawJaggedEdge_(row);
}
/**
* @override
*/
drawValueInput_(row) {
this.highlighter_.drawValueInput(row);
super.drawValueInput_(row);
}
/**
* @override
*/
drawStatementInput_(row) {
this.highlighter_.drawStatementInput(row);
super.drawStatementInput_(row);
}
/**
* @override
*/
drawRightSideRow_(row) {
this.highlighter_.drawRightSideRow(row);
this.outlinePath_ += svgPaths.lineOnAxis('H', row.xPos + row.width) +
svgPaths.lineOnAxis('V', row.yPos + row.height);
}
/**
* @override
*/
drawBottom_() {
this.highlighter_.drawBottomRow(this.info_.bottomRow);
super.drawBottom_();
}
/**
* Add steps for the left side of the block, which may include an output
* connection
* @protected
* @override
*/
drawLeft_() {
this.highlighter_.drawLeft();
super.drawLeft_();
}
/**
* @override
*/
drawInlineInput_(input) {
this.highlighter_.drawInlineInput(/** @type {!InlineInput} */ (input));
super.drawInlineInput_(input);
}
/**
* @override
*/
positionInlineInputConnection_(input) {
const yPos = input.centerline - input.height / 2;
// Move the connection.
if (input.connectionModel) {
// xPos already contains info about startX
let connX =
input.xPos + input.connectionWidth + this.constants_.DARK_PATH_OFFSET;
if (this.info_.RTL) {
connX *= -1;
}
input.connectionModel.setOffsetInBlock(
connX,
yPos + input.connectionOffsetY + this.constants_.DARK_PATH_OFFSET);
}
input.connectionModel.setOffsetInBlock(connX, row.yPos);
}
};
/**
* @override
*/
Drawer.prototype.positionNextConnection_ = function() {
const bottomRow = this.info_.bottomRow;
if (bottomRow.connection) {
const connInfo = bottomRow.connection;
const x = connInfo.xPos; // Already contains info about startX.
const connX =
(this.info_.RTL ? -x : x) + (this.constants_.DARK_PATH_OFFSET / 2);
connInfo.connectionModel.setOffsetInBlock(
connX, bottomRow.baseline + this.constants_.DARK_PATH_OFFSET);
/**
* @override
*/
positionStatementInputConnection_(row) {
const input = row.getLastInput();
if (input.connectionModel) {
let connX = row.xPos + row.statementEdge + input.notchOffset;
if (this.info_.RTL) {
connX *= -1;
} else {
connX += this.constants_.DARK_PATH_OFFSET;
}
input.connectionModel.setOffsetInBlock(
connX, row.yPos + this.constants_.DARK_PATH_OFFSET);
}
}
};
/**
* @override
*/
positionExternalValueConnection_(row) {
const input = row.getLastInput();
if (input.connectionModel) {
let connX = row.xPos + row.width + this.constants_.DARK_PATH_OFFSET;
if (this.info_.RTL) {
connX *= -1;
}
input.connectionModel.setOffsetInBlock(connX, row.yPos);
}
}
/**
* @override
*/
positionNextConnection_() {
const bottomRow = this.info_.bottomRow;
if (bottomRow.connection) {
const connInfo = bottomRow.connection;
const x = connInfo.xPos; // Already contains info about startX.
const connX =
(this.info_.RTL ? -x : x) + (this.constants_.DARK_PATH_OFFSET / 2);
connInfo.connectionModel.setOffsetInBlock(
connX, bottomRow.baseline + this.constants_.DARK_PATH_OFFSET);
}
}
}
exports.Drawer = Drawer;

View File

@@ -25,269 +25,275 @@ const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProv
* Some highlights are simple offsets of the parent paths and can be generated
* programmatically. Others, especially on curves, are just made out of piles
* of constants and are hard to tweak.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @constructor
* @package
* @alias Blockly.geras.HighlightConstantProvider
*/
const HighlightConstantProvider = function(constants) {
class HighlightConstantProvider {
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.geras.HighlightConstantProvider
*/
this.constantProvider = constants;
constructor(constants) {
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
*/
this.constantProvider = constants;
/**
* The offset between the block's main path and highlight path.
* @type {number}
* @package
*/
this.OFFSET = 0.5;
/**
* The start point, which is offset in both X and Y, as an SVG path chunk.
* @type {string}
*/
this.START_POINT = svgPaths.moveBy(this.OFFSET, this.OFFSET);
}
/**
* The offset between the block's main path and highlight path.
* @type {number}
* Initialize shape objects based on the constants set in the constructor.
* @package
*/
this.OFFSET = 0.5;
init() {
/**
* An object containing sizing and path information about inside corner
* highlights.
* @type {!Object}
*/
this.INSIDE_CORNER = this.makeInsideCorner();
/**
* An object containing sizing and path information about outside corner
* highlights.
* @type {!Object}
*/
this.OUTSIDE_CORNER = this.makeOutsideCorner();
/**
* An object containing sizing and path information about puzzle tab
* highlights.
* @type {!Object}
*/
this.PUZZLE_TAB = this.makePuzzleTab();
/**
* An object containing sizing and path information about notch highlights.
* @type {!Object}
*/
this.NOTCH = this.makeNotch();
/**
* An object containing sizing and path information about highlights for
* collapsed block indicators.
* @type {!Object}
*/
this.JAGGED_TEETH = this.makeJaggedTeeth();
/**
* An object containing sizing and path information about start hat
* highlights.
* @type {!Object}
*/
this.START_HAT = this.makeStartHat();
}
/**
* The start point, which is offset in both X and Y, as an SVG path chunk.
* @type {string}
* @return {!Object} An object containing sizing and path information about
* inside corner highlights.
* @package
*/
this.START_POINT = svgPaths.moveBy(this.OFFSET, this.OFFSET);
};
makeInsideCorner() {
const radius = this.constantProvider.CORNER_RADIUS;
const offset = this.OFFSET;
/**
* Initialize shape objects based on the constants set in the constructor.
* @package
*/
HighlightConstantProvider.prototype.init = function() {
/**
* An object containing sizing and path information about inside corner
* highlights.
* @type {!Object}
*/
this.INSIDE_CORNER = this.makeInsideCorner();
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the outside of a curve.
* @const
*/
const distance45outside = (1 - Math.SQRT1_2) * (radius + offset) - offset;
const pathTopRtl = svgPaths.moveBy(distance45outside, distance45outside) +
svgPaths.arc(
'a', '0 0,0', radius,
svgPaths.point(
-distance45outside - offset, radius - distance45outside));
const pathBottomRtl = svgPaths.arc(
'a', '0 0,0', radius + offset,
svgPaths.point(radius + offset, radius + offset));
const pathBottomLtr =
svgPaths.moveBy(distance45outside, -distance45outside) +
svgPaths.arc(
'a', '0 0,0', radius + offset,
svgPaths.point(
radius - distance45outside, distance45outside + offset));
return {
width: radius + offset,
height: radius,
pathTop: function(rtl) {
return rtl ? pathTopRtl : '';
},
pathBottom: function(rtl) {
return rtl ? pathBottomRtl : pathBottomLtr;
},
};
}
/**
* An object containing sizing and path information about outside corner
* highlights.
* @type {!Object}
* @return {!Object} An object containing sizing and path information about
* outside corner highlights.
* @package
*/
this.OUTSIDE_CORNER = this.makeOutsideCorner();
makeOutsideCorner() {
const radius = this.constantProvider.CORNER_RADIUS;
const offset = this.OFFSET;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the inside of a curve.
* @const
*/
const distance45inside = (1 - Math.SQRT1_2) * (radius - offset) + offset;
const topLeftStartX = distance45inside;
const topLeftStartY = distance45inside;
const topLeftCornerHighlightRtl =
svgPaths.moveBy(topLeftStartX, topLeftStartY) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(radius - topLeftStartX, -topLeftStartY + offset));
/**
* SVG path for drawing the highlight on the rounded top-left corner.
* @const
*/
const topLeftCornerHighlightLtr = svgPaths.moveBy(offset, radius) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(radius, -radius + offset));
const bottomLeftStartX = distance45inside;
const bottomLeftStartY = -distance45inside;
const bottomLeftPath = svgPaths.moveBy(bottomLeftStartX, bottomLeftStartY) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(
-bottomLeftStartX + offset, -bottomLeftStartY - radius));
return {
height: radius,
topLeft: function(rtl) {
return rtl ? topLeftCornerHighlightRtl : topLeftCornerHighlightLtr;
},
bottomLeft: function() {
return bottomLeftPath;
},
};
}
/**
* An object containing sizing and path information about puzzle tab
* highlights.
* @type {!Object}
* @return {!Object} An object containing sizing and path information about
* puzzle tab highlights.
* @package
*/
this.PUZZLE_TAB = this.makePuzzleTab();
makePuzzleTab() {
const width = this.constantProvider.TAB_WIDTH;
const height = this.constantProvider.TAB_HEIGHT;
// This is how much of the vertical block edge is actually drawn by the
// puzzle tab.
const verticalOverlap = 2.5;
const highlightRtlUp =
svgPaths.moveBy(-2, -height + verticalOverlap + 0.9) +
svgPaths.lineTo(width * -0.45, -2.1);
const highlightRtlDown = svgPaths.lineOnAxis('v', verticalOverlap) +
svgPaths.moveBy(-width * 0.97, 2.5) +
svgPaths.curve(
'q',
[
svgPaths.point(-width * 0.05, 10),
svgPaths.point(width * 0.3, 9.5),
]) +
svgPaths.moveBy(width * 0.67, -1.9) +
svgPaths.lineOnAxis('v', verticalOverlap);
const highlightLtrUp = svgPaths.lineOnAxis('v', -1.5) +
svgPaths.moveBy(width * -0.92, -0.5) +
svgPaths.curve(
'q',
[svgPaths.point(width * -0.19, -5.5), svgPaths.point(0, -11)]) +
svgPaths.moveBy(width * 0.92, 1);
const highlightLtrDown =
svgPaths.moveBy(-5, height - 0.7) + svgPaths.lineTo(width * 0.46, -2.1);
return {
width: width,
height: height,
pathUp: function(rtl) {
return rtl ? highlightRtlUp : highlightLtrUp;
},
pathDown: function(rtl) {
return rtl ? highlightRtlDown : highlightLtrDown;
},
};
}
/**
* An object containing sizing and path information about notch highlights.
* @type {!Object}
* @return {!Object} An object containing sizing and path information about
* notch highlights.
* @package
*/
this.NOTCH = this.makeNotch();
makeNotch() {
// This is only for the previous connection.
const pathLeft = svgPaths.lineOnAxis('h', this.OFFSET) +
this.constantProvider.NOTCH.pathLeft;
return {pathLeft: pathLeft};
}
/**
* An object containing sizing and path information about highlights for
* collapsed block indicators.
* @type {!Object}
* @return {!Object} An object containing sizing and path information about
* collapsed block edge highlights.
* @package
*/
this.JAGGED_TEETH = this.makeJaggedTeeth();
makeJaggedTeeth() {
const pathLeft = svgPaths.lineTo(5.1, 2.6) + svgPaths.moveBy(-10.2, 6.8) +
svgPaths.lineTo(5.1, 2.6);
return {pathLeft: pathLeft, height: 12, width: 10.2};
}
/**
* An object containing sizing and path information about start hat
* highlights.
* @type {!Object}
* @return {!Object} An object containing sizing and path information about
* start highlights.
* @package
*/
this.START_HAT = this.makeStartHat();
};
makeStartHat() {
const hatHeight = this.constantProvider.START_HAT.height;
const pathRtl = svgPaths.moveBy(25, -8.7) + svgPaths.curve('c', [
svgPaths.point(29.7, -6.2),
svgPaths.point(57.2, -0.5),
svgPaths.point(75, 8.7),
]);
/**
* @return {!Object} An object containing sizing and path information about
* inside corner highlights.
* @package
*/
HighlightConstantProvider.prototype.makeInsideCorner = function() {
const radius = this.constantProvider.CORNER_RADIUS;
const offset = this.OFFSET;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the outside of a curve.
* @const
*/
const distance45outside = (1 - Math.SQRT1_2) * (radius + offset) - offset;
const pathTopRtl = svgPaths.moveBy(distance45outside, distance45outside) +
svgPaths.arc(
'a', '0 0,0', radius,
svgPaths.point(
-distance45outside - offset, radius - distance45outside));
const pathBottomRtl = svgPaths.arc(
'a', '0 0,0', radius + offset,
svgPaths.point(radius + offset, radius + offset));
const pathBottomLtr = svgPaths.moveBy(distance45outside, -distance45outside) +
svgPaths.arc(
'a', '0 0,0', radius + offset,
svgPaths.point(
radius - distance45outside, distance45outside + offset));
return {
width: radius + offset,
height: radius,
pathTop: function(rtl) {
return rtl ? pathTopRtl : '';
},
pathBottom: function(rtl) {
return rtl ? pathBottomRtl : pathBottomLtr;
},
};
};
/**
* @return {!Object} An object containing sizing and path information about
* outside corner highlights.
* @package
*/
HighlightConstantProvider.prototype.makeOutsideCorner = function() {
const radius = this.constantProvider.CORNER_RADIUS;
const offset = this.OFFSET;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the inside of a curve.
* @const
*/
const distance45inside = (1 - Math.SQRT1_2) * (radius - offset) + offset;
const topLeftStartX = distance45inside;
const topLeftStartY = distance45inside;
const topLeftCornerHighlightRtl =
svgPaths.moveBy(topLeftStartX, topLeftStartY) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(radius - topLeftStartX, -topLeftStartY + offset));
/**
* SVG path for drawing the highlight on the rounded top-left corner.
* @const
*/
const topLeftCornerHighlightLtr = svgPaths.moveBy(offset, radius) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(radius, -radius + offset));
const bottomLeftStartX = distance45inside;
const bottomLeftStartY = -distance45inside;
const bottomLeftPath = svgPaths.moveBy(bottomLeftStartX, bottomLeftStartY) +
svgPaths.arc(
'a', '0 0,1', radius - offset,
svgPaths.point(
-bottomLeftStartX + offset, -bottomLeftStartY - radius));
return {
height: radius,
topLeft: function(rtl) {
return rtl ? topLeftCornerHighlightRtl : topLeftCornerHighlightLtr;
},
bottomLeft: function() {
return bottomLeftPath;
},
};
};
/**
* @return {!Object} An object containing sizing and path information about
* puzzle tab highlights.
* @package
*/
HighlightConstantProvider.prototype.makePuzzleTab = function() {
const width = this.constantProvider.TAB_WIDTH;
const height = this.constantProvider.TAB_HEIGHT;
// This is how much of the vertical block edge is actually drawn by the puzzle
// tab.
const verticalOverlap = 2.5;
const highlightRtlUp = svgPaths.moveBy(-2, -height + verticalOverlap + 0.9) +
svgPaths.lineTo(width * -0.45, -2.1);
const highlightRtlDown = svgPaths.lineOnAxis('v', verticalOverlap) +
svgPaths.moveBy(-width * 0.97, 2.5) +
svgPaths.curve(
'q',
[
svgPaths.point(-width * 0.05, 10),
svgPaths.point(width * 0.3, 9.5),
]) +
svgPaths.moveBy(width * 0.67, -1.9) +
svgPaths.lineOnAxis('v', verticalOverlap);
const highlightLtrUp = svgPaths.lineOnAxis('v', -1.5) +
svgPaths.moveBy(width * -0.92, -0.5) +
svgPaths.curve(
'q', [svgPaths.point(width * -0.19, -5.5), svgPaths.point(0, -11)]) +
svgPaths.moveBy(width * 0.92, 1);
const highlightLtrDown =
svgPaths.moveBy(-5, height - 0.7) + svgPaths.lineTo(width * 0.46, -2.1);
return {
width: width,
height: height,
pathUp: function(rtl) {
return rtl ? highlightRtlUp : highlightLtrUp;
},
pathDown: function(rtl) {
return rtl ? highlightRtlDown : highlightLtrDown;
},
};
};
/**
* @return {!Object} An object containing sizing and path information about
* notch highlights.
* @package
*/
HighlightConstantProvider.prototype.makeNotch = function() {
// This is only for the previous connection.
const pathLeft = svgPaths.lineOnAxis('h', this.OFFSET) +
this.constantProvider.NOTCH.pathLeft;
return {pathLeft: pathLeft};
};
/**
* @return {!Object} An object containing sizing and path information about
* collapsed block edge highlights.
* @package
*/
HighlightConstantProvider.prototype.makeJaggedTeeth = function() {
const pathLeft = svgPaths.lineTo(5.1, 2.6) + svgPaths.moveBy(-10.2, 6.8) +
svgPaths.lineTo(5.1, 2.6);
return {pathLeft: pathLeft, height: 12, width: 10.2};
};
/**
* @return {!Object} An object containing sizing and path information about
* start highlights.
* @package
*/
HighlightConstantProvider.prototype.makeStartHat = function() {
const hatHeight = this.constantProvider.START_HAT.height;
const pathRtl = svgPaths.moveBy(25, -8.7) + svgPaths.curve('c', [
svgPaths.point(29.7, -6.2),
svgPaths.point(57.2, -0.5),
svgPaths.point(75, 8.7),
]);
const pathLtr = svgPaths.curve('c', [
svgPaths.point(17.8, -9.2),
svgPaths.point(45.3, -14.9),
svgPaths.point(75, -8.7),
]) + svgPaths.moveTo(100.5, hatHeight + 0.5);
return {
path: function(rtl) {
return rtl ? pathRtl : pathLtr;
},
};
};
const pathLtr = svgPaths.curve('c', [
svgPaths.point(17.8, -9.2),
svgPaths.point(45.3, -14.9),
svgPaths.point(75, -8.7),
]) + svgPaths.moveTo(100.5, hatHeight + 0.5);
return {
path: function(rtl) {
return rtl ? pathRtl : pathLtr;
},
};
}
}
exports.HighlightConstantProvider = HighlightConstantProvider;

View File

@@ -19,13 +19,21 @@ goog.module('Blockly.geras.Highlighter');
const svgPaths = goog.require('Blockly.utils.svgPaths');
/* eslint-disable-next-line no-unused-vars */
const {BottomRow} = goog.require('Blockly.blockRendering.BottomRow');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {HighlightConstantProvider} = goog.requireType('Blockly.geras.HighlightConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {InlineInput} = goog.require('Blockly.geras.InlineInput');
/* eslint-disable-next-line no-unused-vars */
const {RenderInfo} = goog.requireType('Blockly.geras.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {Renderer} = goog.requireType('Blockly.geras.Renderer');
/* eslint-disable-next-line no-unused-vars */
const {Row} = goog.requireType('Blockly.blockRendering.Row');
/* eslint-disable-next-line no-unused-vars */
const {TopRow} = goog.require('Blockly.blockRendering.TopRow');
const {Types} = goog.require('Blockly.blockRendering.Types');
@@ -39,221 +47,264 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
* position of each part of the block. The resulting paths are not continuous
* or closed paths. The highlights for tabs and notches are loosely based on
* tab and notch shapes, but are not exactly the same.
*
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @constructor
* @alias Blockly.geras.Highlighter
*/
const Highlighter = function(info) {
this.info_ = info;
this.steps_ = '';
this.inlineSteps_ = '';
class Highlighter {
/**
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @alias Blockly.geras.Highlighter
*/
constructor(info) {
this.info_ = info;
this.steps_ = '';
this.inlineSteps_ = '';
this.RTL_ = this.info_.RTL;
this.RTL_ = this.info_.RTL;
const renderer = /** @type {!Renderer} */ (info.getRenderer());
const renderer = /** @type {!Renderer} */ (info.getRenderer());
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
*/
this.constants_ = renderer.getConstants();
/**
* @type {!HighlightConstantProvider}
*/
this.highlightConstants_ = renderer.getHighlightConstants();
/**
* The offset between the block's main path and highlight path.
* @type {number}
* @private
*/
this.highlightOffset_ = this.highlightConstants_.OFFSET;
this.outsideCornerPaths_ = this.highlightConstants_.OUTSIDE_CORNER;
this.insideCornerPaths_ = this.highlightConstants_.INSIDE_CORNER;
this.puzzleTabPaths_ = this.highlightConstants_.PUZZLE_TAB;
this.notchPaths_ = this.highlightConstants_.NOTCH;
this.startPaths_ = this.highlightConstants_.START_HAT;
this.jaggedTeethPaths_ = this.highlightConstants_.JAGGED_TEETH;
}
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
* Get the steps for the highlight path.
* @return {string} The steps for the highlight path.
* @package
*/
this.constants_ = renderer.getConstants();
getPath() {
return this.steps_ + '\n' + this.inlineSteps_;
}
/**
* @type {!HighlightConstantProvider}
* Add a highlight to the top corner of a block.
* @param {!TopRow} row The top row of the block.
* @package
*/
this.highlightConstants_ = renderer.getHighlightConstants();
drawTopCorner(row) {
this.steps_ += svgPaths.moveBy(row.xPos, this.info_.startY);
for (let i = 0, elem; (elem = row.elements[i]); i++) {
if (Types.isLeftSquareCorner(elem)) {
this.steps_ += this.highlightConstants_.START_POINT;
} else if (Types.isLeftRoundedCorner(elem)) {
this.steps_ += this.outsideCornerPaths_.topLeft(this.RTL_);
} else if (Types.isPreviousConnection(elem)) {
this.steps_ += this.notchPaths_.pathLeft;
} else if (Types.isHat(elem)) {
this.steps_ += this.startPaths_.path(this.RTL_);
} else if (Types.isSpacer(elem) && elem.width !== 0) {
// The end point of the spacer needs to be offset by the highlight
// amount. So instead of using the spacer's width for a relative
// horizontal, use its width and position for an absolute horizontal
// move.
this.steps_ += svgPaths.lineOnAxis(
'H', elem.xPos + elem.width - this.highlightOffset_);
}
}
const right = row.xPos + row.width - this.highlightOffset_;
this.steps_ += svgPaths.lineOnAxis('H', right);
}
/**
* The offset between the block's main path and highlight path.
* @type {number}
* @private
* Add a highlight on a jagged edge for a collapsed block.
* @param {!Row} row The row to highlight.
* @package
*/
this.highlightOffset_ = this.highlightConstants_.OFFSET;
this.outsideCornerPaths_ = this.highlightConstants_.OUTSIDE_CORNER;
this.insideCornerPaths_ = this.highlightConstants_.INSIDE_CORNER;
this.puzzleTabPaths_ = this.highlightConstants_.PUZZLE_TAB;
this.notchPaths_ = this.highlightConstants_.NOTCH;
this.startPaths_ = this.highlightConstants_.START_HAT;
this.jaggedTeethPaths_ = this.highlightConstants_.JAGGED_TEETH;
};
/**
* Get the steps for the highlight path.
* @return {string} The steps for the highlight path.
* @package
*/
Highlighter.prototype.getPath = function() {
return this.steps_ + '\n' + this.inlineSteps_;
};
Highlighter.prototype.drawTopCorner = function(row) {
this.steps_ += svgPaths.moveBy(row.xPos, this.info_.startY);
for (let i = 0, elem; (elem = row.elements[i]); i++) {
if (Types.isLeftSquareCorner(elem)) {
this.steps_ += this.highlightConstants_.START_POINT;
} else if (Types.isLeftRoundedCorner(elem)) {
this.steps_ += this.outsideCornerPaths_.topLeft(this.RTL_);
} else if (Types.isPreviousConnection(elem)) {
this.steps_ += this.notchPaths_.pathLeft;
} else if (Types.isHat(elem)) {
this.steps_ += this.startPaths_.path(this.RTL_);
} else if (Types.isSpacer(elem) && elem.width !== 0) {
// The end point of the spacer needs to be offset by the highlight amount.
// So instead of using the spacer's width for a relative horizontal, use
// its width and position for an absolute horizontal move.
this.steps_ += svgPaths.lineOnAxis(
'H', elem.xPos + elem.width - this.highlightOffset_);
}
}
const right = row.xPos + row.width - this.highlightOffset_;
this.steps_ += svgPaths.lineOnAxis('H', right);
};
Highlighter.prototype.drawJaggedEdge_ = function(row) {
if (this.info_.RTL) {
const remainder =
row.height - this.jaggedTeethPaths_.height - this.highlightOffset_;
this.steps_ +=
this.jaggedTeethPaths_.pathLeft + svgPaths.lineOnAxis('v', remainder);
}
};
Highlighter.prototype.drawValueInput = function(row) {
const input = row.getLastInput();
if (this.RTL_) {
const belowTabHeight = row.height - input.connectionHeight;
this.steps_ +=
svgPaths.moveTo(
input.xPos + input.width - this.highlightOffset_, row.yPos) +
this.puzzleTabPaths_.pathDown(this.RTL_) +
svgPaths.lineOnAxis('v', belowTabHeight);
} else {
this.steps_ += svgPaths.moveTo(input.xPos + input.width, row.yPos) +
this.puzzleTabPaths_.pathDown(this.RTL_);
}
};
Highlighter.prototype.drawStatementInput = function(row) {
const input = row.getLastInput();
if (this.RTL_) {
const innerHeight = row.height - (2 * this.insideCornerPaths_.height);
this.steps_ += svgPaths.moveTo(input.xPos, row.yPos) +
this.insideCornerPaths_.pathTop(this.RTL_) +
svgPaths.lineOnAxis('v', innerHeight) +
this.insideCornerPaths_.pathBottom(this.RTL_) +
svgPaths.lineTo(
row.width - input.xPos - this.insideCornerPaths_.width, 0);
} else {
this.steps_ += svgPaths.moveTo(input.xPos, row.yPos + row.height) +
this.insideCornerPaths_.pathBottom(this.RTL_) +
svgPaths.lineTo(
row.width - input.xPos - this.insideCornerPaths_.width, 0);
}
};
Highlighter.prototype.drawRightSideRow = function(row) {
const rightEdge = row.xPos + row.width - this.highlightOffset_;
if (row.followsStatement) {
this.steps_ += svgPaths.lineOnAxis('H', rightEdge);
}
if (this.RTL_) {
this.steps_ += svgPaths.lineOnAxis('H', rightEdge);
if (row.height > this.highlightOffset_) {
this.steps_ += svgPaths.lineOnAxis(
'V', row.yPos + row.height - this.highlightOffset_);
}
}
};
Highlighter.prototype.drawBottomRow = function(row) {
// Highlight the vertical edge of the bottom row on the input side.
// Highlighting is always from the top left, both in LTR and RTL.
if (this.RTL_) {
this.steps_ +=
svgPaths.lineOnAxis('V', row.baseline - this.highlightOffset_);
} else {
const cornerElem = this.info_.bottomRow.elements[0];
if (Types.isLeftSquareCorner(cornerElem)) {
this.steps_ += svgPaths.moveTo(
row.xPos + this.highlightOffset_,
row.baseline - this.highlightOffset_);
} else if (Types.isLeftRoundedCorner(cornerElem)) {
this.steps_ += svgPaths.moveTo(row.xPos, row.baseline);
this.steps_ += this.outsideCornerPaths_.bottomLeft();
}
}
};
Highlighter.prototype.drawLeft = function() {
const outputConnection = this.info_.outputConnection;
if (outputConnection) {
const tabBottom =
outputConnection.connectionOffsetY + outputConnection.height;
// Draw a line up to the bottom of the tab.
if (this.RTL_) {
this.steps_ += svgPaths.moveTo(this.info_.startX, tabBottom);
} else {
const left = this.info_.startX + this.highlightOffset_;
const bottom = this.info_.bottomRow.baseline - this.highlightOffset_;
this.steps_ += svgPaths.moveTo(left, bottom);
this.steps_ += svgPaths.lineOnAxis('V', tabBottom);
}
this.steps_ += this.puzzleTabPaths_.pathUp(this.RTL_);
}
if (!this.RTL_) {
const topRow = this.info_.topRow;
if (Types.isLeftRoundedCorner(topRow.elements[0])) {
this.steps_ += svgPaths.lineOnAxis('V', this.outsideCornerPaths_.height);
} else {
drawJaggedEdge_(row) {
if (this.info_.RTL) {
const remainder =
row.height - this.jaggedTeethPaths_.height - this.highlightOffset_;
this.steps_ +=
svgPaths.lineOnAxis('V', topRow.capline + this.highlightOffset_);
this.jaggedTeethPaths_.pathLeft + svgPaths.lineOnAxis('v', remainder);
}
}
};
Highlighter.prototype.drawInlineInput = function(input) {
const offset = this.highlightOffset_;
/**
* Add a highlight on a value input.
* @param {!Row} row The row the input belongs to.
* @package
*/
drawValueInput(row) {
const input = row.getLastInput();
if (this.RTL_) {
const belowTabHeight = row.height - input.connectionHeight;
// Relative to the block's left.
const connectionRight = input.xPos + input.connectionWidth;
const yPos = input.centerline - input.height / 2;
const bottomHighlightWidth = input.width - input.connectionWidth;
const startY = yPos + offset;
if (this.RTL_) {
const aboveTabHeight = input.connectionOffsetY - offset;
const belowTabHeight = input.height -
(input.connectionOffsetY + input.connectionHeight) + offset;
const startX = connectionRight - offset;
this.inlineSteps_ += svgPaths.moveTo(startX, startY) +
// Right edge above tab.
svgPaths.lineOnAxis('v', aboveTabHeight) +
// Back of tab.
this.puzzleTabPaths_.pathDown(this.RTL_) +
// Right edge below tab.
svgPaths.lineOnAxis('v', belowTabHeight) +
// Bottom.
svgPaths.lineOnAxis('h', bottomHighlightWidth);
} else {
this.inlineSteps_ +=
// Go to top right corner.
svgPaths.moveTo(input.xPos + input.width + offset, startY) +
// Highlight right edge, bottom.
svgPaths.lineOnAxis('v', input.height) +
svgPaths.lineOnAxis('h', -bottomHighlightWidth) +
// Go to top of tab.
svgPaths.moveTo(connectionRight, yPos + input.connectionOffsetY) +
// Short highlight glint at bottom of tab.
this.puzzleTabPaths_.pathDown(this.RTL_);
this.steps_ +=
svgPaths.moveTo(
input.xPos + input.width - this.highlightOffset_, row.yPos) +
this.puzzleTabPaths_.pathDown(this.RTL_) +
svgPaths.lineOnAxis('v', belowTabHeight);
} else {
this.steps_ += svgPaths.moveTo(input.xPos + input.width, row.yPos) +
this.puzzleTabPaths_.pathDown(this.RTL_);
}
}
};
/**
* Add a highlight on a statement input.
* @param {!Row} row The row to highlight.
* @package
*/
drawStatementInput(row) {
const input = row.getLastInput();
if (this.RTL_) {
const innerHeight = row.height - (2 * this.insideCornerPaths_.height);
this.steps_ += svgPaths.moveTo(input.xPos, row.yPos) +
this.insideCornerPaths_.pathTop(this.RTL_) +
svgPaths.lineOnAxis('v', innerHeight) +
this.insideCornerPaths_.pathBottom(this.RTL_) +
svgPaths.lineTo(
row.width - input.xPos - this.insideCornerPaths_.width, 0);
} else {
this.steps_ += svgPaths.moveTo(input.xPos, row.yPos + row.height) +
this.insideCornerPaths_.pathBottom(this.RTL_) +
svgPaths.lineTo(
row.width - input.xPos - this.insideCornerPaths_.width, 0);
}
}
/**
* Add a highlight on the right side of a row.
* @param {!Row} row The row to highlight.
* @package
*/
drawRightSideRow(row) {
const rightEdge = row.xPos + row.width - this.highlightOffset_;
if (row.followsStatement) {
this.steps_ += svgPaths.lineOnAxis('H', rightEdge);
}
if (this.RTL_) {
this.steps_ += svgPaths.lineOnAxis('H', rightEdge);
if (row.height > this.highlightOffset_) {
this.steps_ += svgPaths.lineOnAxis(
'V', row.yPos + row.height - this.highlightOffset_);
}
}
}
/**
* Add a highlight to the bottom row.
* @param {!BottomRow} row The row to highlight.
* @package
*/
drawBottomRow(row) {
// Highlight the vertical edge of the bottom row on the input side.
// Highlighting is always from the top left, both in LTR and RTL.
if (this.RTL_) {
this.steps_ +=
svgPaths.lineOnAxis('V', row.baseline - this.highlightOffset_);
} else {
const cornerElem = this.info_.bottomRow.elements[0];
if (Types.isLeftSquareCorner(cornerElem)) {
this.steps_ += svgPaths.moveTo(
row.xPos + this.highlightOffset_,
row.baseline - this.highlightOffset_);
} else if (Types.isLeftRoundedCorner(cornerElem)) {
this.steps_ += svgPaths.moveTo(row.xPos, row.baseline);
this.steps_ += this.outsideCornerPaths_.bottomLeft();
}
}
}
/**
* Draw the highlight on the left side of the block.
* @package
*/
drawLeft() {
const outputConnection = this.info_.outputConnection;
if (outputConnection) {
const tabBottom =
outputConnection.connectionOffsetY + outputConnection.height;
// Draw a line up to the bottom of the tab.
if (this.RTL_) {
this.steps_ += svgPaths.moveTo(this.info_.startX, tabBottom);
} else {
const left = this.info_.startX + this.highlightOffset_;
const bottom = this.info_.bottomRow.baseline - this.highlightOffset_;
this.steps_ += svgPaths.moveTo(left, bottom);
this.steps_ += svgPaths.lineOnAxis('V', tabBottom);
}
this.steps_ += this.puzzleTabPaths_.pathUp(this.RTL_);
}
if (!this.RTL_) {
const topRow = this.info_.topRow;
if (Types.isLeftRoundedCorner(topRow.elements[0])) {
this.steps_ +=
svgPaths.lineOnAxis('V', this.outsideCornerPaths_.height);
} else {
this.steps_ +=
svgPaths.lineOnAxis('V', topRow.capline + this.highlightOffset_);
}
}
}
/**
* Add a highlight to an inline input.
* @param {!InlineInput} input The input to highlight.
* @package
*/
drawInlineInput(input) {
const offset = this.highlightOffset_;
// Relative to the block's left.
const connectionRight = input.xPos + input.connectionWidth;
const yPos = input.centerline - input.height / 2;
const bottomHighlightWidth = input.width - input.connectionWidth;
const startY = yPos + offset;
if (this.RTL_) {
const aboveTabHeight = input.connectionOffsetY - offset;
const belowTabHeight = input.height -
(input.connectionOffsetY + input.connectionHeight) + offset;
const startX = connectionRight - offset;
this.inlineSteps_ += svgPaths.moveTo(startX, startY) +
// Right edge above tab.
svgPaths.lineOnAxis('v', aboveTabHeight) +
// Back of tab.
this.puzzleTabPaths_.pathDown(this.RTL_) +
// Right edge below tab.
svgPaths.lineOnAxis('v', belowTabHeight) +
// Bottom.
svgPaths.lineOnAxis('h', bottomHighlightWidth);
} else {
this.inlineSteps_ +=
// Go to top right corner.
svgPaths.moveTo(input.xPos + input.width + offset, startY) +
// Highlight right edge, bottom.
svgPaths.lineOnAxis('v', input.height) +
svgPaths.lineOnAxis('h', -bottomHighlightWidth) +
// Go to top of tab.
svgPaths.moveTo(connectionRight, yPos + input.connectionOffsetY) +
// Short highlight glint at bottom of tab.
this.puzzleTabPaths_.pathDown(this.RTL_);
}
}
}
exports.Highlighter = Highlighter;

View File

@@ -17,7 +17,6 @@
*/
goog.module('Blockly.geras.RenderInfo');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {ExternalValueInput} = goog.require('Blockly.blockRendering.ExternalValueInput');
@@ -41,425 +40,435 @@ const {inputTypes} = goog.require('Blockly.inputTypes');
* This measure pass does not propagate changes to the block (although fields
* may choose to rerender when getSize() is called). However, calling it
* repeatedly may be expensive.
*
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @constructor
* @package
* @extends {BaseRenderInfo}
* @alias Blockly.geras.RenderInfo
*/
const RenderInfo = function(renderer, block) {
RenderInfo.superClass_.constructor.call(this, renderer, block);
};
object.inherits(RenderInfo, BaseRenderInfo);
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
RenderInfo.prototype.getRenderer = function() {
return /** @type {!Renderer} */ (this.renderer_);
};
/**
* @override
*/
RenderInfo.prototype.populateBottomRow_ = function() {
RenderInfo.superClass_.populateBottomRow_.call(this);
const followsStatement = this.block_.inputList.length &&
this.block_.inputList[this.block_.inputList.length - 1].type ===
inputTypes.STATEMENT;
// The minimum height of the bottom row is smaller in Geras than in other
// renderers, because the dark path adds a pixel.
// If one of the row's elements has a greater height this will be overwritten
// in the compute pass.
if (!followsStatement) {
this.bottomRow.minHeight =
this.constants_.MEDIUM_PADDING - this.constants_.DARK_PATH_OFFSET;
class RenderInfo extends BaseRenderInfo {
/**
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @package
* @alias Blockly.geras.RenderInfo
*/
constructor(renderer, block) {
super(renderer, block);
}
};
/**
* @override
*/
RenderInfo.prototype.addInput_ = function(input, activeRow) {
// Non-dummy inputs have visual representations onscreen.
if (this.isInline && input.type === inputTypes.VALUE) {
activeRow.elements.push(new InlineInput(this.constants_, input));
activeRow.hasInlineInput = true;
} else if (input.type === inputTypes.STATEMENT) {
activeRow.elements.push(new StatementInput(this.constants_, input));
activeRow.hasStatement = true;
} else if (input.type === inputTypes.VALUE) {
activeRow.elements.push(new ExternalValueInput(this.constants_, input));
activeRow.hasExternalInput = true;
} else if (input.type === inputTypes.DUMMY) {
// Dummy inputs have no visual representation, but the information is still
// important.
activeRow.minHeight =
Math.max(activeRow.minHeight, this.constants_.DUMMY_INPUT_MIN_HEIGHT);
activeRow.hasDummyInput = true;
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
getRenderer() {
return /** @type {!Renderer} */ (this.renderer_);
}
// Ignore row alignment if inline.
if (!this.isInline && activeRow.align === null) {
activeRow.align = input.align;
}
};
/**
* @override
*/
RenderInfo.prototype.addElemSpacing_ = function() {
let hasExternalInputs = false;
for (let i = 0, row; (row = this.rows[i]); i++) {
if (row.hasExternalInput) {
hasExternalInputs = true;
/**
* @override
*/
populateBottomRow_() {
super.populateBottomRow_();
const followsStatement = this.block_.inputList.length &&
this.block_.inputList[this.block_.inputList.length - 1].type ===
inputTypes.STATEMENT;
// The minimum height of the bottom row is smaller in Geras than in other
// renderers, because the dark path adds a pixel.
// If one of the row's elements has a greater height this will be
// overwritten in the compute pass.
if (!followsStatement) {
this.bottomRow.minHeight =
this.constants_.MEDIUM_PADDING - this.constants_.DARK_PATH_OFFSET;
}
}
for (let i = 0, row; (row = this.rows[i]); i++) {
const oldElems = row.elements;
row.elements = [];
// No spacing needed before the corner on the top row or the bottom row.
if (row.startsWithElemSpacer()) {
// There's a spacer before the first element in the row.
row.elements.push(new InRowSpacer(
this.constants_, this.getInRowSpacing_(null, oldElems[0])));
/**
* @override
*/
addInput_(input, activeRow) {
// Non-dummy inputs have visual representations onscreen.
if (this.isInline && input.type === inputTypes.VALUE) {
activeRow.elements.push(new InlineInput(this.constants_, input));
activeRow.hasInlineInput = true;
} else if (input.type === inputTypes.STATEMENT) {
activeRow.elements.push(new StatementInput(this.constants_, input));
activeRow.hasStatement = true;
} else if (input.type === inputTypes.VALUE) {
activeRow.elements.push(new ExternalValueInput(this.constants_, input));
activeRow.hasExternalInput = true;
} else if (input.type === inputTypes.DUMMY) {
// Dummy inputs have no visual representation, but the information is
// still important.
activeRow.minHeight =
Math.max(activeRow.minHeight, this.constants_.DUMMY_INPUT_MIN_HEIGHT);
activeRow.hasDummyInput = true;
}
if (!oldElems.length) {
continue;
// Ignore row alignment if inline.
if (!this.isInline && activeRow.align === null) {
activeRow.align = input.align;
}
for (let e = 0; e < oldElems.length - 1; e++) {
row.elements.push(oldElems[e]);
const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
row.elements.push(oldElems[oldElems.length - 1]);
if (row.endsWithElemSpacer()) {
let spacing = this.getInRowSpacing_(oldElems[oldElems.length - 1], null);
if (hasExternalInputs && row.hasDummyInput) {
spacing += this.constants_.TAB_WIDTH;
}
/**
* @override
*/
addElemSpacing_() {
let hasExternalInputs = false;
for (let i = 0, row; (row = this.rows[i]); i++) {
if (row.hasExternalInput) {
hasExternalInputs = true;
}
}
for (let i = 0, row; (row = this.rows[i]); i++) {
const oldElems = row.elements;
row.elements = [];
// No spacing needed before the corner on the top row or the bottom row.
if (row.startsWithElemSpacer()) {
// There's a spacer before the first element in the row.
row.elements.push(new InRowSpacer(
this.constants_, this.getInRowSpacing_(null, oldElems[0])));
}
if (!oldElems.length) {
continue;
}
for (let e = 0; e < oldElems.length - 1; e++) {
row.elements.push(oldElems[e]);
const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
row.elements.push(oldElems[oldElems.length - 1]);
if (row.endsWithElemSpacer()) {
let spacing =
this.getInRowSpacing_(oldElems[oldElems.length - 1], null);
if (hasExternalInputs && row.hasDummyInput) {
spacing += this.constants_.TAB_WIDTH;
}
// There's a spacer after the last element in the row.
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
// There's a spacer after the last element in the row.
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
}
};
/**
* @override
*/
RenderInfo.prototype.getInRowSpacing_ = function(prev, next) {
if (!prev) {
// Between an editable field and the beginning of the row.
if (next && Types.isField(next) &&
(/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Inline input at the beginning of the row.
if (next && Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
}
if (next && Types.isStatementInput(next)) {
return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
}
// Anything else at the beginning of the row.
return this.constants_.LARGE_PADDING;
}
// Spacing between a non-input and the end of the row or a statement input.
if (!Types.isInput(prev) && (!next || Types.isStatementInput(next))) {
// Between an editable field and the end of the row.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Padding at the end of an icon-only row to make the block shape clearer.
if (Types.isIcon(prev)) {
return (this.constants_.LARGE_PADDING * 2) + 1;
}
if (Types.isHat(prev)) {
return this.constants_.NO_PADDING;
}
// Establish a minimum width for a block with a previous or next connection.
if (Types.isPreviousOrNextConnection(prev)) {
/**
* @override
*/
getInRowSpacing_(prev, next) {
if (!prev) {
// Between an editable field and the beginning of the row.
if (next && Types.isField(next) &&
(/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Inline input at the beginning of the row.
if (next && Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
}
if (next && Types.isStatementInput(next)) {
return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
}
// Anything else at the beginning of the row.
return this.constants_.LARGE_PADDING;
}
// Between rounded corner and the end of the row.
if (Types.isLeftRoundedCorner(prev)) {
return this.constants_.MIN_BLOCK_WIDTH;
}
// Between a jagged edge and the end of the row.
if (Types.isJaggedEdge(prev)) {
return this.constants_.NO_PADDING;
}
// Between noneditable fields and icons and the end of the row.
return this.constants_.LARGE_PADDING;
}
// Between inputs and the end of the row.
if (Types.isInput(prev) && !next) {
if (Types.isExternalInput(prev)) {
return this.constants_.NO_PADDING;
} else if (Types.isInlineInput(prev)) {
return this.constants_.LARGE_PADDING;
} else if (Types.isStatementInput(prev)) {
return this.constants_.NO_PADDING;
}
}
// Spacing between a non-input and an input.
if (!Types.isInput(prev) && next && Types.isInput(next)) {
// Between an editable field and an input.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
if (Types.isInlineInput(next)) {
return this.constants_.SMALL_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.SMALL_PADDING;
// Spacing between a non-input and the end of the row or a statement input.
if (!Types.isInput(prev) && (!next || Types.isStatementInput(next))) {
// Between an editable field and the end of the row.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
} else {
if (Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isStatementInput(next)) {
// Padding at the end of an icon-only row to make the block shape clearer.
if (Types.isIcon(prev)) {
return (this.constants_.LARGE_PADDING * 2) + 1;
}
if (Types.isHat(prev)) {
return this.constants_.NO_PADDING;
}
// Establish a minimum width for a block with a previous or next
// connection.
if (Types.isPreviousOrNextConnection(prev)) {
return this.constants_.LARGE_PADDING;
}
// Between rounded corner and the end of the row.
if (Types.isLeftRoundedCorner(prev)) {
return this.constants_.MIN_BLOCK_WIDTH;
}
// Between a jagged edge and the end of the row.
if (Types.isJaggedEdge(prev)) {
return this.constants_.NO_PADDING;
}
// Between noneditable fields and icons and the end of the row.
return this.constants_.LARGE_PADDING;
}
// Between inputs and the end of the row.
if (Types.isInput(prev) && !next) {
if (Types.isExternalInput(prev)) {
return this.constants_.NO_PADDING;
} else if (Types.isInlineInput(prev)) {
return this.constants_.LARGE_PADDING;
} else if (Types.isStatementInput(prev)) {
return this.constants_.NO_PADDING;
}
}
// Spacing between a non-input and an input.
if (!Types.isInput(prev) && next && Types.isInput(next)) {
// Between an editable field and an input.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
if (Types.isInlineInput(next)) {
return this.constants_.SMALL_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.SMALL_PADDING;
}
} else {
if (Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isStatementInput(next)) {
return this.constants_.LARGE_PADDING;
}
}
return this.constants_.LARGE_PADDING - 1;
}
// Spacing between an icon and an icon or field.
if (Types.isIcon(prev) && next && !Types.isInput(next)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between an inline input and a field.
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
// Editable field after inline input.
if ((/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
} else {
// Noneditable field after inline input.
return this.constants_.LARGE_PADDING;
}
}
return this.constants_.LARGE_PADDING - 1;
}
// Spacing between an icon and an icon or field.
if (Types.isIcon(prev) && next && !Types.isInput(next)) {
return this.constants_.LARGE_PADDING;
}
if (Types.isLeftSquareCorner(prev) && next) {
// Spacing between a hat and a corner
if (Types.isHat(next)) {
return this.constants_.NO_PADDING;
}
// Spacing between a square corner and a previous or next connection
if (Types.isPreviousConnection(next)) {
return next.notchOffset;
} else if (Types.isNextConnection(next)) {
// Next connections are shifted slightly to the left (in both LTR and
// RTL) to make the dark path under the previous connection show
// through.
const offset =
(this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2;
return next.notchOffset + offset;
}
}
// Spacing between an inline input and a field.
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
// Editable field after inline input.
if ((/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
} else {
// Noneditable field after inline input.
// Spacing between a rounded corner and a previous or next connection.
if (Types.isLeftRoundedCorner(prev) && next) {
if (Types.isPreviousConnection(next)) {
return next.notchOffset - this.constants_.CORNER_RADIUS;
} else if (Types.isNextConnection(next)) {
// Next connections are shifted slightly to the left (in both LTR and
// RTL) to make the dark path under the previous connection show
// through.
const offset =
(this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2;
return next.notchOffset - this.constants_.CORNER_RADIUS + offset;
}
}
// Spacing between two fields of the same editability.
if (Types.isField(prev) && next && Types.isField(next) &&
((/** @type {Field} */ (prev)).isEditable ===
(/** @type {Field} */ (next)).isEditable)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between anything and a jagged edge.
if (next && Types.isJaggedEdge(next)) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
}
if (Types.isLeftSquareCorner(prev) && next) {
// Spacing between a hat and a corner
if (Types.isHat(next)) {
/**
* @override
*/
getSpacerRowHeight_(prev, next) {
// If we have an empty block add a spacer to increase the height.
if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
}
// Top and bottom rows act as a spacer so we don't need any extra padding.
if (Types.isTopRow(prev) || Types.isBottomRow(next)) {
return this.constants_.NO_PADDING;
}
// Spacing between a square corner and a previous or next connection
if (Types.isPreviousConnection(next)) {
return next.notchOffset;
} else if (Types.isNextConnection(next)) {
// Next connections are shifted slightly to the left (in both LTR and RTL)
// to make the dark path under the previous connection show through.
const offset = (this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2;
return next.notchOffset + offset;
if (prev.hasExternalInput && next.hasExternalInput) {
return this.constants_.LARGE_PADDING;
}
}
// Spacing between a rounded corner and a previous or next connection.
if (Types.isLeftRoundedCorner(prev) && next) {
if (Types.isPreviousConnection(next)) {
return next.notchOffset - this.constants_.CORNER_RADIUS;
} else if (Types.isNextConnection(next)) {
// Next connections are shifted slightly to the left (in both LTR and RTL)
// to make the dark path under the previous connection show through.
const offset = (this.RTL ? 1 : -1) * this.constants_.DARK_PATH_OFFSET / 2;
return next.notchOffset - this.constants_.CORNER_RADIUS + offset;
if (!prev.hasStatement && next.hasStatement) {
return this.constants_.BETWEEN_STATEMENT_PADDING_Y;
}
}
// Spacing between two fields of the same editability.
if (Types.isField(prev) && next && Types.isField(next) &&
((/** @type {Field} */ (prev)).isEditable ===
(/** @type {Field} */ (next)).isEditable)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between anything and a jagged edge.
if (next && Types.isJaggedEdge(next)) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
};
/**
* @override
*/
RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) {
// If we have an empty block add a spacer to increase the height.
if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
}
// Top and bottom rows act as a spacer so we don't need any extra padding.
if (Types.isTopRow(prev) || Types.isBottomRow(next)) {
return this.constants_.NO_PADDING;
}
if (prev.hasExternalInput && next.hasExternalInput) {
return this.constants_.LARGE_PADDING;
}
if (!prev.hasStatement && next.hasStatement) {
return this.constants_.BETWEEN_STATEMENT_PADDING_Y;
}
if (prev.hasStatement && next.hasStatement) {
return this.constants_.LARGE_PADDING;
}
if (!prev.hasStatement && next.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
if (prev.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
};
/**
* @override
*/
RenderInfo.prototype.getElemCenterline_ = function(row, elem) {
if (Types.isSpacer(elem)) {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
if (prev.hasStatement && next.hasStatement) {
return this.constants_.LARGE_PADDING;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
if (!prev.hasStatement && next.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
return row.capline + elem.height / 2;
}
let result = row.yPos;
if (Types.isField(elem) || Types.isIcon(elem)) {
result += (elem.height / 2);
if ((row.hasInlineInput || row.hasStatement) &&
elem.height + this.constants_.TALL_INPUT_FIELD_OFFSET_Y <= row.height) {
result += this.constants_.TALL_INPUT_FIELD_OFFSET_Y;
if (prev.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
} else if (Types.isInlineInput(elem)) {
result += elem.height / 2;
} else {
result += (row.height / 2);
}
return result;
};
/**
* @override
*/
RenderInfo.prototype.alignRowElements_ = function() {
if (!this.isInline) {
RenderInfo.superClass_.alignRowElements_.call(this);
return;
return this.constants_.MEDIUM_PADDING;
}
// Walk backgrounds through rows on the block, keeping track of the right
// input edge.
let nextRightEdge = 0;
let prevInput = null;
for (let i = this.rows.length - 1, row; (row = this.rows[i]); i--) {
row.nextRightEdge = nextRightEdge;
if (Types.isInputRow(row)) {
if (row.hasStatement) {
this.alignStatementRow_(
/** @type {!InputRow} */ (row));
/**
* @override
*/
getElemCenterline_(row, elem) {
if (Types.isSpacer(elem)) {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
}
if (prevInput && prevInput.hasStatement && row.width < prevInput.width) {
row.nextRightEdge = prevInput.width;
} else {
nextRightEdge = row.width;
}
prevInput = row;
return baseline - elem.height / 2;
}
}
// Walk down each row from the top, comparing the prev and next right input
// edges and setting the desired width to the max of the two.
let prevRightEdge = 0;
for (let i = 0, row; (row = this.rows[i]); i++) {
if (row.hasStatement) {
prevRightEdge = this.getDesiredRowWidth_(row);
} else if (Types.isSpacer(row)) {
// Set the spacer row to the max of the prev or next input width.
row.width = Math.max(prevRightEdge, row.nextRightEdge);
if (Types.isTopRow(row)) {
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
}
return row.capline + elem.height / 2;
}
let result = row.yPos;
if (Types.isField(elem) || Types.isIcon(elem)) {
result += (elem.height / 2);
if ((row.hasInlineInput || row.hasStatement) &&
elem.height + this.constants_.TALL_INPUT_FIELD_OFFSET_Y <=
row.height) {
result += this.constants_.TALL_INPUT_FIELD_OFFSET_Y;
}
} else if (Types.isInlineInput(elem)) {
result += elem.height / 2;
} else {
const currentWidth = row.width;
const desiredWidth = Math.max(prevRightEdge, row.nextRightEdge);
const missingSpace = desiredWidth - currentWidth;
if (missingSpace > 0) {
this.addAlignmentPadding_(row, missingSpace);
result += (row.height / 2);
}
return result;
}
/**
* @override
*/
alignRowElements_() {
if (!this.isInline) {
super.alignRowElements_();
return;
}
// Walk backgrounds through rows on the block, keeping track of the right
// input edge.
let nextRightEdge = 0;
let prevInput = null;
for (let i = this.rows.length - 1, row; (row = this.rows[i]); i--) {
row.nextRightEdge = nextRightEdge;
if (Types.isInputRow(row)) {
if (row.hasStatement) {
this.alignStatementRow_(
/** @type {!InputRow} */ (row));
}
if (prevInput && prevInput.hasStatement &&
row.width < prevInput.width) {
row.nextRightEdge = prevInput.width;
} else {
nextRightEdge = row.width;
}
prevInput = row;
}
}
// Walk down each row from the top, comparing the prev and next right input
// edges and setting the desired width to the max of the two.
let prevRightEdge = 0;
for (let i = 0, row; (row = this.rows[i]); i++) {
if (row.hasStatement) {
prevRightEdge = this.getDesiredRowWidth_(row);
} else if (Types.isSpacer(row)) {
// Set the spacer row to the max of the prev or next input width.
row.width = Math.max(prevRightEdge, row.nextRightEdge);
} else {
const currentWidth = row.width;
const desiredWidth = Math.max(prevRightEdge, row.nextRightEdge);
const missingSpace = desiredWidth - currentWidth;
if (missingSpace > 0) {
this.addAlignmentPadding_(row, missingSpace);
}
prevRightEdge = row.width;
}
prevRightEdge = row.width;
}
}
};
/**
* @override
*/
RenderInfo.prototype.getDesiredRowWidth_ = function(row) {
// Limit the width of a statement row when a block is inline.
if (this.isInline && row.hasStatement) {
return this.statementEdge + this.constants_.MAX_BOTTOM_WIDTH + this.startX;
}
return RenderInfo.superClass_.getDesiredRowWidth_.call(this, row);
};
/**
* @override
*/
RenderInfo.prototype.finalize_ = function() {
// Performance note: this could be combined with the draw pass, if the time
// that this takes is excessive. But it shouldn't be, because it only
// accesses and sets properties that already exist on the objects.
let widestRowWithConnectedBlocks = 0;
let yCursor = 0;
for (let i = 0, row; (row = this.rows[i]); i++) {
row.yPos = yCursor;
row.xPos = this.startX;
yCursor += row.height;
widestRowWithConnectedBlocks =
Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks);
// Add padding to the bottom row if block height is less than minimum
const heightWithoutHat = yCursor - this.topRow.ascenderHeight;
if (row === this.bottomRow &&
heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) {
// But the hat height shouldn't be part of this.
const diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat;
this.bottomRow.height += diff;
yCursor += diff;
/**
* @override
*/
getDesiredRowWidth_(row) {
// Limit the width of a statement row when a block is inline.
if (this.isInline && row.hasStatement) {
return this.statementEdge + this.constants_.MAX_BOTTOM_WIDTH +
this.startX;
}
this.recordElemPositions_(row);
}
if (this.outputConnection && this.block_.nextConnection &&
this.block_.nextConnection.isConnected()) {
// Include width of connected block in value to stack width measurement.
widestRowWithConnectedBlocks = Math.max(
widestRowWithConnectedBlocks,
this.block_.nextConnection.targetBlock().getHeightWidth().width -
this.constants_.DARK_PATH_OFFSET);
return super.getDesiredRowWidth_(row);
}
this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight;
/**
* @override
*/
finalize_() {
// Performance note: this could be combined with the draw pass, if the time
// that this takes is excessive. But it shouldn't be, because it only
// accesses and sets properties that already exist on the objects.
let widestRowWithConnectedBlocks = 0;
let yCursor = 0;
for (let i = 0, row; (row = this.rows[i]); i++) {
row.yPos = yCursor;
row.xPos = this.startX;
yCursor += row.height;
// The dark (lowlight) adds to the size of the block in both x and y.
this.widthWithChildren = widestRowWithConnectedBlocks + this.startX +
this.constants_.DARK_PATH_OFFSET;
this.width += this.constants_.DARK_PATH_OFFSET;
this.height = yCursor + this.constants_.DARK_PATH_OFFSET;
this.startY = this.topRow.capline;
};
widestRowWithConnectedBlocks =
Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks);
// Add padding to the bottom row if block height is less than minimum
const heightWithoutHat = yCursor - this.topRow.ascenderHeight;
if (row === this.bottomRow &&
heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) {
// But the hat height shouldn't be part of this.
const diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat;
this.bottomRow.height += diff;
yCursor += diff;
}
this.recordElemPositions_(row);
}
if (this.outputConnection && this.block_.nextConnection &&
this.block_.nextConnection.isConnected()) {
// Include width of connected block in value to stack width measurement.
widestRowWithConnectedBlocks = Math.max(
widestRowWithConnectedBlocks,
this.block_.nextConnection.targetBlock().getHeightWidth().width -
this.constants_.DARK_PATH_OFFSET);
}
this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight;
// The dark (lowlight) adds to the size of the block in both x and y.
this.widthWithChildren = widestRowWithConnectedBlocks + this.startX +
this.constants_.DARK_PATH_OFFSET;
this.width += this.constants_.DARK_PATH_OFFSET;
this.height = yCursor + this.constants_.DARK_PATH_OFFSET;
this.startY = this.topRow.capline;
}
}
exports.RenderInfo = RenderInfo;

View File

@@ -17,7 +17,6 @@
*/
goog.module('Blockly.geras.InlineInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InlineInput: BaseInlineInput} = goog.require('Blockly.blockRendering.InlineInput');
@@ -27,26 +26,28 @@ const {Input} = goog.requireType('Blockly.Input');
/**
* An object containing information about the space an inline input takes up
* during rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The inline input to measure and store
* information for.
* @package
* @constructor
* during rendering.
* @extends {BaseInlineInput}
* @alias Blockly.geras.InlineInput
*/
const InlineInput = function(constants, input) {
InlineInput.superClass_.constructor.call(this, constants, input);
class InlineInput extends BaseInlineInput {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The inline input to measure and store
* information for.
* @package
* @alias Blockly.geras.InlineInput
*/
constructor(constants, input) {
super(constants, input);
if (this.connectedBlock) {
// We allow the dark path to show on the parent block so that the child
// block looks embossed. This takes up an extra pixel in both x and y.
this.width += this.constants_.DARK_PATH_OFFSET;
this.height += this.constants_.DARK_PATH_OFFSET;
if (this.connectedBlock) {
// We allow the dark path to show on the parent block so that the child
// block looks embossed. This takes up an extra pixel in both x and y.
this.width += this.constants_.DARK_PATH_OFFSET;
this.height += this.constants_.DARK_PATH_OFFSET;
}
}
};
object.inherits(InlineInput, BaseInlineInput);
}
exports.InlineInput = InlineInput;

View File

@@ -17,7 +17,6 @@
*/
goog.module('Blockly.geras.StatementInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
@@ -27,25 +26,27 @@ const {StatementInput: BaseStatementInput} = goog.require('Blockly.blockRenderin
/**
* An object containing information about the space a statement input takes up
* during rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The statement input to measure and store
* information for.
* @package
* @constructor
* during rendering.
* @extends {BaseStatementInput}
* @alias Blockly.geras.StatementInput
*/
const StatementInput = function(constants, input) {
StatementInput.superClass_.constructor.call(this, constants, input);
class StatementInput extends BaseStatementInput {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The statement input to measure and store
* information for.
* @package
* @alias Blockly.geras.StatementInput
*/
constructor(constants, input) {
super(constants, input);
if (this.connectedBlock) {
// We allow the dark path to show on the parent block so that the child
// block looks embossed. This takes up an extra pixel in both x and y.
this.height += this.constants_.DARK_PATH_OFFSET;
if (this.connectedBlock) {
// We allow the dark path to show on the parent block so that the child
// block looks embossed. This takes up an extra pixel in both x and y.
this.height += this.constants_.DARK_PATH_OFFSET;
}
}
};
object.inherits(StatementInput, BaseStatementInput);
}
exports.StatementInput = StatementInput;

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.geras.Renderer');
const blockRendering = goog.require('Blockly.blockRendering');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
@@ -35,116 +34,115 @@ const {Theme} = goog.requireType('Blockly.Theme');
/**
* The geras renderer.
* @param {string} name The renderer name.
* @package
* @constructor
* @extends {BaseRenderer}
* @alias Blockly.geras.Renderer
*/
const Renderer = function(name) {
Renderer.superClass_.constructor.call(this, name);
class Renderer extends BaseRenderer {
/**
* @param {string} name The renderer name.
* @package
* @alias Blockly.geras.Renderer
*/
constructor(name) {
super(name);
/**
* The renderer's highlight constant provider.
* @type {HighlightConstantProvider}
* @private
*/
this.highlightConstants_ = null;
}
/**
* The renderer's highlight constant provider.
* @type {HighlightConstantProvider}
* @private
* Initialize the renderer. Geras has a highlight provider in addition to
* the normal constant provider.
* @package
* @override
*/
this.highlightConstants_ = null;
};
object.inherits(Renderer, BaseRenderer);
init(theme, opt_rendererOverrides) {
super.init(theme, opt_rendererOverrides);
this.highlightConstants_ = this.makeHighlightConstants_();
this.highlightConstants_.init();
}
/**
* Initialize the renderer. Geras has a highlight provider in addition to
* the normal constant provider.
* @package
* @override
*/
Renderer.prototype.init = function(theme, opt_rendererOverrides) {
Renderer.superClass_.init.call(this, theme, opt_rendererOverrides);
this.highlightConstants_ = this.makeHighlightConstants_();
this.highlightConstants_.init();
};
/**
* @override
*/
refreshDom(svg, theme) {
super.refreshDom(svg, theme);
this.getHighlightConstants().init();
}
/**
* @override
*/
Renderer.prototype.refreshDom = function(svg, theme) {
Renderer.superClass_.refreshDom.call(this, svg, theme);
this.getHighlightConstants().init();
};
/**
* @override
*/
makeConstants_() {
return new ConstantProvider();
}
/**
* @override
*/
Renderer.prototype.makeConstants_ = function() {
return new ConstantProvider();
};
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
makeRenderInfo_(block) {
return new RenderInfo(this, block);
}
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
Renderer.prototype.makeRenderInfo_ = function(block) {
return new RenderInfo(this, block);
};
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all information needed
* to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
makeDrawer_(block, info) {
return new Drawer(
block,
/** @type {!RenderInfo} */ (info));
}
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all
* information needed to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
Renderer.prototype.makeDrawer_ = function(block, info) {
return new Drawer(
block,
/** @type {!RenderInfo} */ (info));
};
/**
* Create a new instance of a renderer path object.
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for colouring.
* @return {!PathObject} The renderer path object.
* @package
* @override
*/
makePathObject(root, style) {
return new PathObject(
root, style,
/** @type {!ConstantProvider} */ (this.getConstants()));
}
/**
* Create a new instance of a renderer path object.
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for
* colouring.
* @return {!PathObject} The renderer path object.
* @package
* @override
*/
Renderer.prototype.makePathObject = function(root, style) {
return new PathObject(
root, style,
/** @type {!ConstantProvider} */ (this.getConstants()));
};
/**
* Create a new instance of the renderer's highlight constant provider.
* @return {!HighlightConstantProvider} The highlight constant provider.
* @protected
*/
makeHighlightConstants_() {
return new HighlightConstantProvider(
/** @type {!BaseConstantProvider} */
(this.getConstants()));
}
/**
* Create a new instance of the renderer's highlight constant provider.
* @return {!HighlightConstantProvider} The highlight constant
* provider.
* @protected
*/
Renderer.prototype.makeHighlightConstants_ = function() {
return new HighlightConstantProvider(
/** @type {!BaseConstantProvider} */
(this.getConstants()));
};
/**
* Get the renderer's highlight constant provider. We assume that when this is
* called, the renderer has already been initialized.
* @return {!HighlightConstantProvider} The highlight constant
* provider.
* @package
*/
Renderer.prototype.getHighlightConstants = function() {
return (
/** @type {!HighlightConstantProvider} */
(this.highlightConstants_));
};
/**
* Get the renderer's highlight constant provider. We assume that when this
* is called, the renderer has already been initialized.
* @return {!HighlightConstantProvider} The highlight constant provider.
* @package
*/
getHighlightConstants() {
return (
/** @type {!HighlightConstantProvider} */
(this.highlightConstants_));
}
}
blockRendering.register('geras', Renderer);

View File

@@ -17,20 +17,21 @@
*/
goog.module('Blockly.minimalist.ConstantProvider');
const object = goog.require('Blockly.utils.object');
const {ConstantProvider: BaseConstantProvider} = goog.require('Blockly.blockRendering.ConstantProvider');
/**
* An object that provides constants for rendering blocks in the sample.
* @constructor
* @package
* @extends {BaseConstantProvider}
* @alias Blockly.minimalist.ConstantProvider
*/
const ConstantProvider = function() {
ConstantProvider.superClass_.constructor.call(this);
};
object.inherits(ConstantProvider, BaseConstantProvider);
class ConstantProvider extends BaseConstantProvider {
/**
* @package
* @alias Blockly.minimalist.ConstantProvider
*/
constructor() {
super();
}
}
exports.ConstantProvider = ConstantProvider;

View File

@@ -15,7 +15,6 @@
*/
goog.module('Blockly.minimalist.Drawer');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Drawer: BaseDrawer} = goog.require('Blockly.blockRendering.Drawer');
@@ -25,17 +24,19 @@ const {RenderInfo} = goog.requireType('Blockly.minimalist.RenderInfo');
/**
* An object that draws a block based on the given rendering information.
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @constructor
* @extends {BaseDrawer}
* @alias Blockly.minimalist.Drawer
*/
const Drawer = function(block, info) {
Drawer.superClass_.constructor.call(this, block, info);
};
object.inherits(Drawer, BaseDrawer);
class Drawer extends BaseDrawer {
/**
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @alias Blockly.minimalist.Drawer
*/
constructor(block, info) {
super(block, info);
}
}
exports.Drawer = Drawer;

View File

@@ -15,7 +15,6 @@
*/
goog.module('Blockly.minimalist.RenderInfo');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {RenderInfo: BaseRenderInfo} = goog.require('Blockly.blockRendering.RenderInfo');
@@ -29,26 +28,27 @@ const {Renderer} = goog.requireType('Blockly.minimalist.Renderer');
* This measure pass does not propagate changes to the block (although fields
* may choose to rerender when getSize() is called). However, calling it
* repeatedly may be expensive.
*
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @constructor
* @package
* @extends {BaseRenderInfo}
* @alias Blockly.minimalist.RenderInfo
*/
const RenderInfo = function(renderer, block) {
RenderInfo.superClass_.constructor.call(this, renderer, block);
};
object.inherits(RenderInfo, BaseRenderInfo);
class RenderInfo extends BaseRenderInfo {
/**
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @package
* @alias Blockly.minimalist.RenderInfo
*/
constructor(renderer, block) {
super(renderer, block);
}
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
RenderInfo.prototype.getRenderer = function() {
return /** @type {!Renderer} */ (this.renderer_);
};
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
getRenderer() {
return /** @type {!Renderer} */ (this.renderer_);
}
}
exports.RenderInfo = RenderInfo;

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.minimalist.Renderer');
const blockRendering = goog.require('Blockly.blockRendering');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {ConstantProvider} = goog.require('Blockly.minimalist.ConstantProvider');
@@ -29,50 +28,52 @@ const {Renderer: BaseRenderer} = goog.require('Blockly.blockRendering.Renderer')
/**
* The minimalist renderer.
* @param {string} name The renderer name.
* @package
* @constructor
* @extends {BaseRenderer}
* @alias Blockly.minimalist.Renderer
*/
const Renderer = function(name) {
Renderer.superClass_.constructor.call(this, name);
};
object.inherits(Renderer, BaseRenderer);
class Renderer extends BaseRenderer {
/**
* @param {string} name The renderer name.
* @package
* @alias Blockly.minimalist.Renderer
*/
constructor(name) {
super(name);
}
/**
* Create a new instance of the renderer's constant provider.
* @return {!ConstantProvider} The constant provider.
* @protected
* @override
*/
Renderer.prototype.makeConstants_ = function() {
return new ConstantProvider();
};
/**
* Create a new instance of the renderer's constant provider.
* @return {!ConstantProvider} The constant provider.
* @protected
* @override
*/
makeConstants_() {
return new ConstantProvider();
}
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
Renderer.prototype.makeRenderInfo_ = function(block) {
return new RenderInfo(this, block);
};
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
makeRenderInfo_(block) {
return new RenderInfo(this, block);
}
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all
* information needed to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
Renderer.prototype.makeDrawer_ = function(block, info) {
return new Drawer(block, /** @type {!RenderInfo} */ (info));
};
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all
* information needed to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
makeDrawer_(block, info) {
return new Drawer(block, /** @type {!RenderInfo} */ (info));
}
}
blockRendering.register('minimalist', Renderer);

View File

@@ -17,7 +17,6 @@
*/
goog.module('Blockly.thrasos.RenderInfo');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
@@ -35,295 +34,299 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
* This measure pass does not propagate changes to the block (although fields
* may choose to rerender when getSize() is called). However, calling it
* repeatedly may be expensive.
*
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @constructor
* @package
* @extends {BaseRenderInfo}
* @alias Blockly.thrasos.RenderInfo
*/
const RenderInfo = function(renderer, block) {
RenderInfo.superClass_.constructor.call(this, renderer, block);
};
object.inherits(RenderInfo, BaseRenderInfo);
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
RenderInfo.prototype.getRenderer = function() {
return /** @type {!Renderer} */ (this.renderer_);
};
/**
* @override
*/
RenderInfo.prototype.addElemSpacing_ = function() {
let hasExternalInputs = false;
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
if (row.hasExternalInput) {
hasExternalInputs = true;
break;
}
class RenderInfo extends BaseRenderInfo {
/**
* @param {!Renderer} renderer The renderer in use.
* @param {!BlockSvg} block The block to measure.
* @package
* @alias Blockly.thrasos.RenderInfo
*/
constructor(renderer, block) {
super(renderer, block);
}
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
const oldElems = row.elements;
row.elements = [];
// No spacing needed before the corner on the top row or the bottom row.
if (row.startsWithElemSpacer()) {
// There's a spacer before the first element in the row.
row.elements.push(new InRowSpacer(
this.constants_, this.getInRowSpacing_(null, oldElems[0])));
}
for (let e = 0; e < oldElems.length - 1; e++) {
row.elements.push(oldElems[e]);
const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
row.elements.push(oldElems[oldElems.length - 1]);
if (row.endsWithElemSpacer()) {
let spacing = this.getInRowSpacing_(oldElems[oldElems.length - 1], null);
if (hasExternalInputs && row.hasDummyInput) {
spacing += this.constants_.TAB_WIDTH;
/**
* Get the block renderer in use.
* @return {!Renderer} The block renderer in use.
* @package
*/
getRenderer() {
return /** @type {!Renderer} */ (this.renderer_);
}
/**
* @override
*/
addElemSpacing_() {
let hasExternalInputs = false;
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
if (row.hasExternalInput) {
hasExternalInputs = true;
break;
}
}
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
const oldElems = row.elements;
row.elements = [];
// No spacing needed before the corner on the top row or the bottom row.
if (row.startsWithElemSpacer()) {
// There's a spacer before the first element in the row.
row.elements.push(new InRowSpacer(
this.constants_, this.getInRowSpacing_(null, oldElems[0])));
}
for (let e = 0; e < oldElems.length - 1; e++) {
row.elements.push(oldElems[e]);
const spacing = this.getInRowSpacing_(oldElems[e], oldElems[e + 1]);
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
row.elements.push(oldElems[oldElems.length - 1]);
if (row.endsWithElemSpacer()) {
let spacing =
this.getInRowSpacing_(oldElems[oldElems.length - 1], null);
if (hasExternalInputs && row.hasDummyInput) {
spacing += this.constants_.TAB_WIDTH;
}
// There's a spacer after the last element in the row.
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
// There's a spacer after the last element in the row.
row.elements.push(new InRowSpacer(this.constants_, spacing));
}
}
};
/**
* @override
*/
RenderInfo.prototype.getInRowSpacing_ = function(prev, next) {
if (!prev) {
// Between an editable field and the beginning of the row.
if (next && Types.isField(next) &&
(/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Inline input at the beginning of the row.
if (next && Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
}
if (next && Types.isStatementInput(next)) {
return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
}
// Anything else at the beginning of the row.
return this.constants_.LARGE_PADDING;
}
// Spacing between a non-input and the end of the row.
if (!Types.isInput(prev) && !next) {
// Between an editable field and the end of the row.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Padding at the end of an icon-only row to make the block shape clearer.
if (Types.isIcon(prev)) {
return (this.constants_.LARGE_PADDING * 2) + 1;
}
if (Types.isHat(prev)) {
return this.constants_.NO_PADDING;
}
// Establish a minimum width for a block with a previous or next connection.
if (Types.isPreviousOrNextConnection(prev)) {
/**
* @override
*/
getInRowSpacing_(prev, next) {
if (!prev) {
// Between an editable field and the beginning of the row.
if (next && Types.isField(next) &&
(/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
// Inline input at the beginning of the row.
if (next && Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
}
if (next && Types.isStatementInput(next)) {
return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
}
// Anything else at the beginning of the row.
return this.constants_.LARGE_PADDING;
}
// Between rounded corner and the end of the row.
if (Types.isLeftRoundedCorner(prev)) {
return this.constants_.MIN_BLOCK_WIDTH;
}
// Between a jagged edge and the end of the row.
if (Types.isJaggedEdge(prev)) {
return this.constants_.NO_PADDING;
}
// Between noneditable fields and icons and the end of the row.
return this.constants_.LARGE_PADDING;
}
// Between inputs and the end of the row.
if (Types.isInput(prev) && !next) {
if (Types.isExternalInput(prev)) {
return this.constants_.NO_PADDING;
} else if (Types.isInlineInput(prev)) {
return this.constants_.LARGE_PADDING;
} else if (Types.isStatementInput(prev)) {
return this.constants_.NO_PADDING;
}
}
// Spacing between a non-input and an input.
if (!Types.isInput(prev) && next && Types.isInput(next)) {
// Between an editable field and an input.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
if (Types.isInlineInput(next)) {
return this.constants_.SMALL_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.SMALL_PADDING;
// Spacing between a non-input and the end of the row.
if (!Types.isInput(prev) && !next) {
// Between an editable field and the end of the row.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
return this.constants_.MEDIUM_PADDING;
}
} else {
if (Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isStatementInput(next)) {
// Padding at the end of an icon-only row to make the block shape clearer.
if (Types.isIcon(prev)) {
return (this.constants_.LARGE_PADDING * 2) + 1;
}
if (Types.isHat(prev)) {
return this.constants_.NO_PADDING;
}
// Establish a minimum width for a block with a previous or next
// connection.
if (Types.isPreviousOrNextConnection(prev)) {
return this.constants_.LARGE_PADDING;
}
// Between rounded corner and the end of the row.
if (Types.isLeftRoundedCorner(prev)) {
return this.constants_.MIN_BLOCK_WIDTH;
}
// Between a jagged edge and the end of the row.
if (Types.isJaggedEdge(prev)) {
return this.constants_.NO_PADDING;
}
// Between noneditable fields and icons and the end of the row.
return this.constants_.LARGE_PADDING;
}
// Between inputs and the end of the row.
if (Types.isInput(prev) && !next) {
if (Types.isExternalInput(prev)) {
return this.constants_.NO_PADDING;
} else if (Types.isInlineInput(prev)) {
return this.constants_.LARGE_PADDING;
} else if (Types.isStatementInput(prev)) {
return this.constants_.NO_PADDING;
}
}
// Spacing between a non-input and an input.
if (!Types.isInput(prev) && next && Types.isInput(next)) {
// Between an editable field and an input.
if (Types.isField(prev) && (/** @type {Field} */ (prev)).isEditable) {
if (Types.isInlineInput(next)) {
return this.constants_.SMALL_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.SMALL_PADDING;
}
} else {
if (Types.isInlineInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isExternalInput(next)) {
return this.constants_.MEDIUM_LARGE_PADDING;
} else if (Types.isStatementInput(next)) {
return this.constants_.LARGE_PADDING;
}
}
return this.constants_.LARGE_PADDING - 1;
}
// Spacing between an icon and an icon or field.
if (Types.isIcon(prev) && next && !Types.isInput(next)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between an inline input and a field.
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
// Editable field after inline input.
if ((/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
} else {
// Noneditable field after inline input.
return this.constants_.LARGE_PADDING;
}
}
return this.constants_.LARGE_PADDING - 1;
}
// Spacing between an icon and an icon or field.
if (Types.isIcon(prev) && next && !Types.isInput(next)) {
return this.constants_.LARGE_PADDING;
}
if (Types.isLeftSquareCorner(prev) && next) {
// Spacing between a hat and a corner
if (Types.isHat(next)) {
return this.constants_.NO_PADDING;
}
// Spacing between a square corner and a previous or next connection
if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
return next.notchOffset;
}
}
// Spacing between an inline input and a field.
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
// Editable field after inline input.
if ((/** @type {Field} */ (next)).isEditable) {
return this.constants_.MEDIUM_PADDING;
} else {
// Noneditable field after inline input.
// Spacing between a rounded corner and a previous or next connection.
if (Types.isLeftRoundedCorner(prev) && next) {
return next.notchOffset - this.constants_.CORNER_RADIUS;
}
// Spacing between two fields of the same editability.
if (Types.isField(prev) && next && Types.isField(next) &&
((/** @type {Field} */ (prev)).isEditable ===
(/** @type {Field} */ (next)).isEditable)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between anything and a jagged edge.
if (next && Types.isJaggedEdge(next)) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
}
if (Types.isLeftSquareCorner(prev) && next) {
// Spacing between a hat and a corner
if (Types.isHat(next)) {
/**
* @override
*/
getSpacerRowHeight_(prev, next) {
// If we have an empty block add a spacer to increase the height.
if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
}
// Top and bottom rows act as a spacer so we don't need any extra padding.
if (Types.isTopRow(prev) || Types.isBottomRow(next)) {
return this.constants_.NO_PADDING;
}
// Spacing between a square corner and a previous or next connection
if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
return next.notchOffset;
if (prev.hasExternalInput && next.hasExternalInput) {
return this.constants_.LARGE_PADDING;
}
}
// Spacing between a rounded corner and a previous or next connection.
if (Types.isLeftRoundedCorner(prev) && next) {
return next.notchOffset - this.constants_.CORNER_RADIUS;
}
// Spacing between two fields of the same editability.
if (Types.isField(prev) && next && Types.isField(next) &&
((/** @type {Field} */ (prev)).isEditable ===
(/** @type {Field} */ (next)).isEditable)) {
return this.constants_.LARGE_PADDING;
}
// Spacing between anything and a jagged edge.
if (next && Types.isJaggedEdge(next)) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
};
/**
* @override
*/
RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) {
// If we have an empty block add a spacer to increase the height.
if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
}
// Top and bottom rows act as a spacer so we don't need any extra padding.
if (Types.isTopRow(prev) || Types.isBottomRow(next)) {
return this.constants_.NO_PADDING;
}
if (prev.hasExternalInput && next.hasExternalInput) {
return this.constants_.LARGE_PADDING;
}
if (!prev.hasStatement && next.hasStatement) {
return this.constants_.BETWEEN_STATEMENT_PADDING_Y;
}
if (prev.hasStatement && next.hasStatement) {
return this.constants_.LARGE_PADDING;
}
if (prev.hasDummyInput || next.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
return this.constants_.MEDIUM_PADDING;
};
/**
* @override
*/
RenderInfo.prototype.getElemCenterline_ = function(row, elem) {
if (Types.isSpacer(elem)) {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
if (!prev.hasStatement && next.hasStatement) {
return this.constants_.BETWEEN_STATEMENT_PADDING_Y;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
if (prev.hasStatement && next.hasStatement) {
return this.constants_.LARGE_PADDING;
}
return row.capline + elem.height / 2;
}
let result = row.yPos;
if (Types.isField(elem) && row.hasStatement) {
const offset = this.constants_.TALL_INPUT_FIELD_OFFSET_Y + elem.height / 2;
result += offset;
} else {
result += (row.height / 2);
}
return result;
};
/**
* @override
*/
RenderInfo.prototype.finalize_ = function() {
// Performance note: this could be combined with the draw pass, if the time
// that this takes is excessive. But it shouldn't be, because it only
// accesses and sets properties that already exist on the objects.
let widestRowWithConnectedBlocks = 0;
let yCursor = 0;
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
row.yPos = yCursor;
row.xPos = this.startX;
yCursor += row.height;
widestRowWithConnectedBlocks =
Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks);
// Add padding to the bottom row if block height is less than minimum
const heightWithoutHat = yCursor - this.topRow.ascenderHeight;
if (row === this.bottomRow &&
heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) {
// But the hat height shouldn't be part of this.
const diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat;
this.bottomRow.height += diff;
yCursor += diff;
if (prev.hasDummyInput || next.hasDummyInput) {
return this.constants_.LARGE_PADDING;
}
this.recordElemPositions_(row);
}
if (this.outputConnection && this.block_.nextConnection &&
this.block_.nextConnection.isConnected()) {
// Include width of connected block in value to stack width measurement.
widestRowWithConnectedBlocks = Math.max(
widestRowWithConnectedBlocks,
this.block_.nextConnection.targetBlock().getHeightWidth().width);
return this.constants_.MEDIUM_PADDING;
}
this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight;
this.widthWithChildren = widestRowWithConnectedBlocks + this.startX;
/**
* @override
*/
getElemCenterline_(row, elem) {
if (Types.isSpacer(elem)) {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
}
return row.capline + elem.height / 2;
}
this.height = yCursor;
this.startY = this.topRow.capline;
};
let result = row.yPos;
if (Types.isField(elem) && row.hasStatement) {
const offset =
this.constants_.TALL_INPUT_FIELD_OFFSET_Y + elem.height / 2;
result += offset;
} else {
result += (row.height / 2);
}
return result;
}
/**
* @override
*/
finalize_() {
// Performance note: this could be combined with the draw pass, if the time
// that this takes is excessive. But it shouldn't be, because it only
// accesses and sets properties that already exist on the objects.
let widestRowWithConnectedBlocks = 0;
let yCursor = 0;
for (let i = 0; i < this.rows.length; i++) {
const row = this.rows[i];
row.yPos = yCursor;
row.xPos = this.startX;
yCursor += row.height;
widestRowWithConnectedBlocks =
Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks);
// Add padding to the bottom row if block height is less than minimum
const heightWithoutHat = yCursor - this.topRow.ascenderHeight;
if (row === this.bottomRow &&
heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) {
// But the hat height shouldn't be part of this.
const diff = this.constants_.MIN_BLOCK_HEIGHT - heightWithoutHat;
this.bottomRow.height += diff;
yCursor += diff;
}
this.recordElemPositions_(row);
}
if (this.outputConnection && this.block_.nextConnection &&
this.block_.nextConnection.isConnected()) {
// Include width of connected block in value to stack width measurement.
widestRowWithConnectedBlocks = Math.max(
widestRowWithConnectedBlocks,
this.block_.nextConnection.targetBlock().getHeightWidth().width);
}
this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight;
this.widthWithChildren = widestRowWithConnectedBlocks + this.startX;
this.height = yCursor;
this.startY = this.topRow.capline;
}
}
exports.RenderInfo = RenderInfo;

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.thrasos.Renderer');
const blockRendering = goog.require('Blockly.blockRendering');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {RenderInfo} = goog.require('Blockly.thrasos.RenderInfo');
@@ -25,28 +24,29 @@ const {Renderer: BaseRenderer} = goog.require('Blockly.blockRendering.Renderer')
/**
* The thrasos renderer.
* @param {string} name The renderer name.
* @package
* @constructor
* @extends {BaseRenderer}
* @alias Blockly.thrasos.Renderer
*/
const Renderer = function(name) {
Renderer.superClass_.constructor.call(this, name);
};
object.inherits(Renderer, BaseRenderer);
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
Renderer.prototype.makeRenderInfo_ = function(block) {
return new RenderInfo(this, block);
};
class Renderer extends BaseRenderer {
/**
* @param {string} name The renderer name.
* @package
* @alias Blockly.thrasos.Renderer
*/
constructor(name) {
super(name);
}
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
makeRenderInfo_(block) {
return new RenderInfo(this, block);
}
}
blockRendering.register('thrasos', Renderer);

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.zelos.Drawer');
const debug = goog.require('Blockly.blockRendering.debug');
const object = goog.require('Blockly.utils.object');
const svgPaths = goog.require('Blockly.utils.svgPaths');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
@@ -31,203 +30,206 @@ const {Row} = goog.requireType('Blockly.blockRendering.Row');
/**
* An object that draws a block based on the given rendering information.
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @constructor
* @extends {BaseDrawer}
* @alias Blockly.zelos.Drawer
*/
const Drawer = function(block, info) {
Drawer.superClass_.constructor.call(this, block, info);
};
object.inherits(Drawer, BaseDrawer);
/**
* @override
*/
Drawer.prototype.draw = function() {
const pathObject =
/** @type {!PathObject} */ (this.block_.pathObject);
pathObject.beginDrawing();
this.hideHiddenIcons_();
this.drawOutline_();
this.drawInternals_();
pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
if (this.info_.RTL) {
pathObject.flipRTL();
class Drawer extends BaseDrawer {
/**
* @param {!BlockSvg} block The block to render.
* @param {!RenderInfo} info An object containing all
* information needed to render this block.
* @package
* @alias Blockly.zelos.Drawer
*/
constructor(block, info) {
super(block, info);
}
if (debug.isDebuggerEnabled()) {
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
}
this.recordSizeOnBlock_();
if (this.info_.outputConnection) {
// Store the output connection shape type for parent blocks to use during
// rendering.
pathObject.outputShapeType = this.info_.outputConnection.shape.type;
}
pathObject.endDrawing();
};
/**
* @override
*/
Drawer.prototype.drawOutline_ = function() {
if (this.info_.outputConnection &&
this.info_.outputConnection.isDynamicShape &&
!this.info_.hasStatementInput &&
!this.info_.bottomRow.hasNextConnection) {
this.drawFlatTop_();
this.drawRightDynamicConnection_();
this.drawFlatBottom_();
this.drawLeftDynamicConnection_();
} else {
Drawer.superClass_.drawOutline_.call(this);
}
};
/**
* @override
*/
draw() {
const pathObject =
/** @type {!PathObject} */ (this.block_.pathObject);
pathObject.beginDrawing();
this.hideHiddenIcons_();
this.drawOutline_();
this.drawInternals_();
/**
* @override
*/
Drawer.prototype.drawLeft_ = function() {
if (this.info_.outputConnection &&
this.info_.outputConnection.isDynamicShape) {
this.drawLeftDynamicConnection_();
} else {
Drawer.superClass_.drawLeft_.call(this);
pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
if (this.info_.RTL) {
pathObject.flipRTL();
}
if (debug.isDebuggerEnabled()) {
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
}
this.recordSizeOnBlock_();
if (this.info_.outputConnection) {
// Store the output connection shape type for parent blocks to use during
// rendering.
pathObject.outputShapeType = this.info_.outputConnection.shape.type;
}
pathObject.endDrawing();
}
};
/**
* Add steps for the right side of a row that does not have value or
* statement input connections.
* @param {!Row} row The row to draw the
* side of.
* @protected
*/
Drawer.prototype.drawRightSideRow_ = function(row) {
if (row.height <= 0) {
return;
/**
* @override
*/
drawOutline_() {
if (this.info_.outputConnection &&
this.info_.outputConnection.isDynamicShape &&
!this.info_.hasStatementInput &&
!this.info_.bottomRow.hasNextConnection) {
this.drawFlatTop_();
this.drawRightDynamicConnection_();
this.drawFlatBottom_();
this.drawLeftDynamicConnection_();
} else {
super.drawOutline_();
}
}
if (row.precedesStatement || row.followsStatement) {
const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight;
const remainingHeight =
row.height - (row.precedesStatement ? cornerHeight : 0);
this.outlinePath_ +=
(row.followsStatement ? this.constants_.INSIDE_CORNERS.pathBottomRight :
/**
* @override
*/
drawLeft_() {
if (this.info_.outputConnection &&
this.info_.outputConnection.isDynamicShape) {
this.drawLeftDynamicConnection_();
} else {
super.drawLeft_();
}
}
/**
* Add steps for the right side of a row that does not have value or
* statement input connections.
* @param {!Row} row The row to draw the
* side of.
* @protected
*/
drawRightSideRow_(row) {
if (row.height <= 0) {
return;
}
if (row.precedesStatement || row.followsStatement) {
const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight;
const remainingHeight =
row.height - (row.precedesStatement ? cornerHeight : 0);
this.outlinePath_ += (row.followsStatement ?
this.constants_.INSIDE_CORNERS.pathBottomRight :
'') +
(remainingHeight > 0 ?
svgPaths.lineOnAxis('V', row.yPos + remainingHeight) :
'') +
(row.precedesStatement ? this.constants_.INSIDE_CORNERS.pathTopRight :
'');
} else {
this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
}
};
/**
* Add steps to draw the right side of an output with a dynamic connection.
* @protected
*/
Drawer.prototype.drawRightDynamicConnection_ = function() {
this.outlinePath_ += this.info_.outputConnection.shape.pathRightDown(
this.info_.outputConnection.height);
};
/**
* Add steps to draw the left side of an output with a dynamic connection.
* @protected
*/
Drawer.prototype.drawLeftDynamicConnection_ = function() {
this.positionOutputConnection_();
this.outlinePath_ += this.info_.outputConnection.shape.pathUp(
this.info_.outputConnection.height);
// Close off the path. This draws a vertical line up to the start of the
// block's path, which may be either a rounded or a sharp corner.
this.outlinePath_ += 'z';
};
/**
* Add steps to draw a flat top row.
* @protected
*/
Drawer.prototype.drawFlatTop_ = function() {
const topRow = this.info_.topRow;
this.positionPreviousConnection_();
this.outlinePath_ += svgPaths.moveBy(topRow.xPos, this.info_.startY);
this.outlinePath_ += svgPaths.lineOnAxis('h', topRow.width);
};
/**
* Add steps to draw a flat bottom row.
* @protected
*/
Drawer.prototype.drawFlatBottom_ = function() {
const bottomRow = this.info_.bottomRow;
this.positionNextConnection_();
this.outlinePath_ += svgPaths.lineOnAxis('V', bottomRow.baseline);
this.outlinePath_ += svgPaths.lineOnAxis('h', -bottomRow.width);
};
/**
* @override
*/
Drawer.prototype.drawInlineInput_ = function(input) {
this.positionInlineInputConnection_(input);
const inputName = input.input.name;
if (input.connectedBlock || this.info_.isInsertionMarker) {
return;
(remainingHeight > 0 ?
svgPaths.lineOnAxis('V', row.yPos + remainingHeight) :
'') +
(row.precedesStatement ? this.constants_.INSIDE_CORNERS.pathTopRight :
'');
} else {
this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
}
}
const width = input.width - (input.connectionWidth * 2);
const height = input.height;
const yPos = input.centerline - height / 2;
/**
* Add steps to draw the right side of an output with a dynamic connection.
* @protected
*/
drawRightDynamicConnection_() {
this.outlinePath_ += this.info_.outputConnection.shape.pathRightDown(
this.info_.outputConnection.height);
}
const connectionRight = input.xPos + input.connectionWidth;
/**
* Add steps to draw the left side of an output with a dynamic connection.
* @protected
*/
drawLeftDynamicConnection_() {
this.positionOutputConnection_();
const outlinePath = svgPaths.moveTo(connectionRight, yPos) +
svgPaths.lineOnAxis('h', width) +
input.shape.pathRightDown(input.height) +
svgPaths.lineOnAxis('h', -width) + input.shape.pathUp(input.height) + 'z';
this.block_.pathObject.setOutlinePath(inputName, outlinePath);
};
this.outlinePath_ += this.info_.outputConnection.shape.pathUp(
this.info_.outputConnection.height);
/**
* @override
*/
Drawer.prototype.drawStatementInput_ = function(row) {
const input = row.getLastInput();
// Where to start drawing the notch, which is on the right side in LTR.
const x = input.xPos + input.notchOffset + input.shape.width;
// Close off the path. This draws a vertical line up to the start of the
// block's path, which may be either a rounded or a sharp corner.
this.outlinePath_ += 'z';
}
const innerTopLeftCorner = input.shape.pathRight +
svgPaths.lineOnAxis(
'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
this.constants_.INSIDE_CORNERS.pathTop;
/**
* Add steps to draw a flat top row.
* @protected
*/
drawFlatTop_() {
const topRow = this.info_.topRow;
this.positionPreviousConnection_();
const innerHeight = row.height - (2 * this.constants_.INSIDE_CORNERS.height);
this.outlinePath_ += svgPaths.moveBy(topRow.xPos, this.info_.startY);
const innerBottomLeftCorner = this.constants_.INSIDE_CORNERS.pathBottom +
svgPaths.lineOnAxis(
'h', (input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
(input.connectedBottomNextConnection ? '' : input.shape.pathLeft);
this.outlinePath_ += svgPaths.lineOnAxis('h', topRow.width);
}
this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
svgPaths.lineOnAxis('v', innerHeight) + innerBottomLeftCorner +
svgPaths.lineOnAxis('H', row.xPos + row.width);
/**
* Add steps to draw a flat bottom row.
* @protected
*/
drawFlatBottom_() {
const bottomRow = this.info_.bottomRow;
this.positionNextConnection_();
this.positionStatementInputConnection_(row);
};
this.outlinePath_ += svgPaths.lineOnAxis('V', bottomRow.baseline);
this.outlinePath_ += svgPaths.lineOnAxis('h', -bottomRow.width);
}
/**
* @override
*/
drawInlineInput_(input) {
this.positionInlineInputConnection_(input);
const inputName = input.input.name;
if (input.connectedBlock || this.info_.isInsertionMarker) {
return;
}
const width = input.width - (input.connectionWidth * 2);
const height = input.height;
const yPos = input.centerline - height / 2;
const connectionRight = input.xPos + input.connectionWidth;
const outlinePath = svgPaths.moveTo(connectionRight, yPos) +
svgPaths.lineOnAxis('h', width) +
input.shape.pathRightDown(input.height) +
svgPaths.lineOnAxis('h', -width) + input.shape.pathUp(input.height) +
'z';
this.block_.pathObject.setOutlinePath(inputName, outlinePath);
}
/**
* @override
*/
drawStatementInput_(row) {
const input = row.getLastInput();
// Where to start drawing the notch, which is on the right side in LTR.
const x = input.xPos + input.notchOffset + input.shape.width;
const innerTopLeftCorner = input.shape.pathRight +
svgPaths.lineOnAxis(
'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
this.constants_.INSIDE_CORNERS.pathTop;
const innerHeight =
row.height - (2 * this.constants_.INSIDE_CORNERS.height);
const innerBottomLeftCorner = this.constants_.INSIDE_CORNERS.pathBottom +
svgPaths.lineOnAxis(
'h', (input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
(input.connectedBottomNextConnection ? '' : input.shape.pathLeft);
this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
svgPaths.lineOnAxis('v', innerHeight) + innerBottomLeftCorner +
svgPaths.lineOnAxis('H', row.xPos + row.width);
this.positionStatementInputConnection_(row);
}
}
exports.Drawer = Drawer;

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.zelos.MarkerSvg');
const dom = goog.require('Blockly.utils.dom');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ASTNode} = goog.requireType('Blockly.ASTNode');
/* eslint-disable-next-line no-unused-vars */
@@ -35,131 +34,140 @@ const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
/**
* Class to draw a marker.
* @param {!WorkspaceSvg} workspace The workspace the marker belongs to.
* @param {!ConstantProvider} constants The constants for
* the renderer.
* @param {!Marker} marker The marker to draw.
* @constructor
* @extends {BaseMarkerSvg}
* @alias Blockly.zelos.MarkerSvg
*/
const MarkerSvg = function(workspace, constants, marker) {
MarkerSvg.superClass_.constructor.call(this, workspace, constants, marker);
};
object.inherits(MarkerSvg, BaseMarkerSvg);
class MarkerSvg extends BaseMarkerSvg {
/**
* @param {!WorkspaceSvg} workspace The workspace the marker belongs to.
* @param {!ConstantProvider} constants The constants for
* the renderer.
* @param {!Marker} marker The marker to draw.
* @alias Blockly.zelos.MarkerSvg
*/
constructor(workspace, constants, marker) {
super(workspace, constants, marker);
/**
* Position and display the marker for an input or an output connection.
* @param {!ASTNode} curNode The node to draw the marker for.
* @private
*/
MarkerSvg.prototype.showWithInputOutput_ = function(curNode) {
const block = /** @type {!BlockSvg} */ (curNode.getSourceBlock());
const connection = /** @type {!Connection} */ (curNode.getLocation());
const offsetInBlock = connection.getOffsetInBlock();
this.positionCircle_(offsetInBlock.x, offsetInBlock.y);
this.setParent_(block);
this.showCurrent_();
};
/**
* @override
*/
MarkerSvg.prototype.showWithOutput_ = function(curNode) {
this.showWithInputOutput_(curNode);
};
/**
* @override
*/
MarkerSvg.prototype.showWithInput_ = function(curNode) {
this.showWithInputOutput_(curNode);
};
/**
* Draw a rectangle around the block.
* @param {!ASTNode} curNode The current node of the marker.
*/
MarkerSvg.prototype.showWithBlock_ = function(curNode) {
const block = /** @type {!BlockSvg} */ (curNode.getLocation());
// Gets the height and width of entire stack.
const heightWidth = block.getHeightWidth();
// Add padding so that being on a stack looks different than being on a block.
this.positionRect_(0, 0, heightWidth.width, heightWidth.height);
this.setParent_(block);
this.showCurrent_();
};
/**
* Position the circle we use for input and output connections.
* @param {number} x The x position of the circle.
* @param {number} y The y position of the circle.
* @private
*/
MarkerSvg.prototype.positionCircle_ = function(x, y) {
this.markerCircle_.setAttribute('cx', x);
this.markerCircle_.setAttribute('cy', y);
this.currentMarkerSvg = this.markerCircle_;
};
/**
* @override
*/
MarkerSvg.prototype.hide = function() {
MarkerSvg.superClass_.hide.call(this);
this.markerCircle_.style.display = 'none';
};
/**
* @override
*/
MarkerSvg.prototype.createDomInternal_ = function() {
/* clang-format off */
/* This markup will be generated and added to the .svgGroup_:
<g>
<rect width="100" height="5">
<animate attributeType="XML" attributeName="fill" dur="1s"
values="transparent;transparent;#fff;transparent" repeatCount="indefinite" />
</rect>
</g>
*/
/* clang-format on */
MarkerSvg.superClass_.createDomInternal_.call(this);
this.markerCircle_ = dom.createSvgElement(
Svg.CIRCLE, {
'r': this.constants_.CURSOR_RADIUS,
'style': 'display: none',
'stroke-width': this.constants_.CURSOR_STROKE_WIDTH,
},
this.markerSvg_);
// Markers and stack cursors don't blink.
if (this.isCursor()) {
const blinkProperties = this.getBlinkProperties_();
dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerCircle_);
/**
* @type {SVGCircleElement}
* @private
*/
this.markerCircle_ = null;
}
return this.markerSvg_;
};
/**
* Position and display the marker for an input or an output connection.
* @param {!ASTNode} curNode The node to draw the marker for.
* @private
*/
showWithInputOutput_(curNode) {
const block = /** @type {!BlockSvg} */ (curNode.getSourceBlock());
const connection = /** @type {!Connection} */ (curNode.getLocation());
const offsetInBlock = connection.getOffsetInBlock();
/**
* @override
*/
MarkerSvg.prototype.applyColour_ = function(curNode) {
MarkerSvg.superClass_.applyColour_.call(this, curNode);
this.markerCircle_.setAttribute('fill', this.colour_);
this.markerCircle_.setAttribute('stroke', this.colour_);
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerCircle_.firstChild.setAttribute('values', values);
this.positionCircle_(offsetInBlock.x, offsetInBlock.y);
this.setParent_(block);
this.showCurrent_();
}
};
/**
* @override
*/
showWithOutput_(curNode) {
this.showWithInputOutput_(curNode);
}
/**
* @override
*/
showWithInput_(curNode) {
this.showWithInputOutput_(curNode);
}
/**
* Draw a rectangle around the block.
* @param {!ASTNode} curNode The current node of the marker.
*/
showWithBlock_(curNode) {
const block = /** @type {!BlockSvg} */ (curNode.getLocation());
// Gets the height and width of entire stack.
const heightWidth = block.getHeightWidth();
// Add padding so that being on a stack looks different than being on a
// block.
this.positionRect_(0, 0, heightWidth.width, heightWidth.height);
this.setParent_(block);
this.showCurrent_();
}
/**
* Position the circle we use for input and output connections.
* @param {number} x The x position of the circle.
* @param {number} y The y position of the circle.
* @private
*/
positionCircle_(x, y) {
this.markerCircle_.setAttribute('cx', x);
this.markerCircle_.setAttribute('cy', y);
this.currentMarkerSvg = this.markerCircle_;
}
/**
* @override
*/
hide() {
super.hide();
this.markerCircle_.style.display = 'none';
}
/**
* @override
*/
createDomInternal_() {
/* clang-format off */
/* This markup will be generated and added to the .svgGroup_:
<g>
<rect width="100" height="5">
<animate attributeType="XML" attributeName="fill" dur="1s"
values="transparent;transparent;#fff;transparent" repeatCount="indefinite" />
</rect>
</g>
*/
/* clang-format on */
super.createDomInternal_();
this.markerCircle_ = dom.createSvgElement(
Svg.CIRCLE, {
'r': this.constants_.CURSOR_RADIUS,
'style': 'display: none',
'stroke-width': this.constants_.CURSOR_STROKE_WIDTH,
},
this.markerSvg_);
// Markers and stack cursors don't blink.
if (this.isCursor()) {
const blinkProperties = this.getBlinkProperties_();
dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerCircle_);
}
return this.markerSvg_;
}
/**
* @override
*/
applyColour_(curNode) {
super.applyColour_(curNode);
this.markerCircle_.setAttribute('fill', this.colour_);
this.markerCircle_.setAttribute('stroke', this.colour_);
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerCircle_.firstChild.setAttribute('values', values);
}
}
}
exports.MarkerSvg = MarkerSvg;

View File

@@ -15,7 +15,6 @@
*/
goog.module('Blockly.zelos.BottomRow');
const object = goog.require('Blockly.utils.object');
const {BottomRow: BaseBottomRow} = goog.require('Blockly.blockRendering.BottomRow');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
@@ -26,40 +25,42 @@ const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProv
* a block as well as spacing information for the top row.
* Elements in a bottom row can consist of corners, spacers and next
* connections.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {BaseBottomRow}
* @alias Blockly.zelos.BottomRow
*/
const BottomRow = function(constants) {
BottomRow.superClass_.constructor.call(this, constants);
};
object.inherits(BottomRow, BaseBottomRow);
class BottomRow extends BaseBottomRow {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.zelos.BottomRow
*/
constructor(constants) {
super(constants);
}
/**
* @override
*/
BottomRow.prototype.endsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
endsWithElemSpacer() {
return false;
}
/**
* Render a round corner unless the block has an output connection.
* @override
*/
BottomRow.prototype.hasLeftSquareCorner = function(block) {
return !!block.outputConnection;
};
/**
* Render a round corner unless the block has an output connection.
* @override
*/
hasLeftSquareCorner(block) {
return !!block.outputConnection;
}
/**
* Render a round corner unless the block has an output connection.
* @override
*/
BottomRow.prototype.hasRightSquareCorner = function(block) {
return !!block.outputConnection && !block.statementInputCount &&
!block.nextConnection;
};
/**
* Render a round corner unless the block has an output connection.
* @override
*/
hasRightSquareCorner(block) {
return !!block.outputConnection && !block.statementInputCount &&
!block.nextConnection;
}
}
exports.BottomRow = BottomRow;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.zelos.StatementInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
@@ -26,31 +25,33 @@ const {StatementInput: BaseStatementInput} = goog.require('Blockly.blockRenderin
/**
* An object containing information about the space a statement input takes up
* during rendering
* @param {!ConstantProvider} constants The rendering constants provider.
* @param {!Input} input The statement input to measure and store information
* for.
* @package
* @constructor
* during rendering.
* @extends {BaseStatementInput}
* @alias Blockly.zelos.StatementInput
*/
const StatementInput = function(constants, input) {
StatementInput.superClass_.constructor.call(this, constants, input);
class StatementInput extends BaseStatementInput {
/**
* @param {!ConstantProvider} constants The rendering constants provider.
* @param {!Input} input The statement input to measure and store information
* for.
* @package
* @alias Blockly.zelos.StatementInput
*/
constructor(constants, input) {
super(constants, input);
if (this.connectedBlock) {
// Find the bottom-most connected block in the stack.
let block = this.connectedBlock;
let nextBlock;
while ((nextBlock = block.getNextBlock())) {
block = nextBlock;
}
if (!block.nextConnection) {
this.height = this.connectedBlockHeight;
this.connectedBottomNextConnection = true;
if (this.connectedBlock) {
// Find the bottom-most connected block in the stack.
let block = this.connectedBlock;
let nextBlock;
while ((nextBlock = block.getNextBlock())) {
block = nextBlock;
}
if (!block.nextConnection) {
this.height = this.connectedBlockHeight;
this.connectedBottomNextConnection = true;
}
}
}
};
object.inherits(StatementInput, BaseStatementInput);
}
exports.StatementInput = StatementInput;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.zelos.RightConnectionShape');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {Measurable} = goog.require('Blockly.blockRendering.Measurable');
@@ -26,20 +25,22 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a right connection shape
* takes up during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.zelos.RightConnectionShape
*/
const RightConnectionShape = function(constants) {
RightConnectionShape.superClass_.constructor.call(this, constants);
this.type |= Types.getType('RIGHT_CONNECTION');
// Size is dynamic
this.height = 0;
this.width = 0;
};
object.inherits(RightConnectionShape, Measurable);
class RightConnectionShape extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.zelos.RightConnectionShape
*/
constructor(constants) {
super(constants);
this.type |= Types.getType('RIGHT_CONNECTION');
// Size is dynamic
this.height = 0;
this.width = 0;
}
}
exports.RightConnectionShape = RightConnectionShape;

View File

@@ -15,7 +15,6 @@
*/
goog.module('Blockly.zelos.TopRow');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {TopRow: BaseTopRow} = goog.require('Blockly.blockRendering.TopRow');
@@ -28,43 +27,45 @@ const {TopRow: BaseTopRow} = goog.require('Blockly.blockRendering.TopRow');
* connections.
* After this constructor is called, the row will contain all non-spacer
* elements it needs.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {BaseTopRow}
* @alias Blockly.zelos.TopRow
*/
const TopRow = function(constants) {
TopRow.superClass_.constructor.call(this, constants);
};
object.inherits(TopRow, BaseTopRow);
class TopRow extends BaseTopRow {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.zelos.TopRow
*/
constructor(constants) {
super(constants);
}
/**
* @override
*/
TopRow.prototype.endsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
endsWithElemSpacer() {
return false;
}
/**
* Render a round corner unless the block has an output connection.
* @override
*/
TopRow.prototype.hasLeftSquareCorner = function(block) {
const hasHat =
(block.hat ? block.hat === 'cap' : this.constants_.ADD_START_HATS) &&
!block.outputConnection && !block.previousConnection;
return !!block.outputConnection || hasHat;
};
/**
* Render a round corner unless the block has an output connection.
* @override
*/
hasLeftSquareCorner(block) {
const hasHat =
(block.hat ? block.hat === 'cap' : this.constants_.ADD_START_HATS) &&
!block.outputConnection && !block.previousConnection;
return !!block.outputConnection || hasHat;
}
/**
* Render a round corner unless the block has an output connection.
* @override
*/
TopRow.prototype.hasRightSquareCorner = function(block) {
return !!block.outputConnection && !block.statementInputCount &&
!block.nextConnection;
};
/**
* Render a round corner unless the block has an output connection.
* @override
*/
hasRightSquareCorner(block) {
return !!block.outputConnection && !block.statementInputCount &&
!block.nextConnection;
}
}
exports.TopRow = TopRow;

View File

@@ -17,7 +17,6 @@
goog.module('Blockly.zelos.PathObject');
const dom = goog.require('Blockly.utils.dom');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.zelos.ConstantProvider');
const {PathObject: BasePathObject} = goog.require('Blockly.blockRendering.PathObject');
@@ -29,218 +28,221 @@ const {Theme} = goog.requireType('Blockly.Theme');
/**
* An object that handles creating and setting each of the SVG elements
* used by the renderer.
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for
* colouring.
* @param {!ConstantProvider} constants The renderer's constants.
* @constructor
* @extends {BasePathObject}
* @package
* @alias Blockly.zelos.PathObject
*/
const PathObject = function(root, style, constants) {
PathObject.superClass_.constructor.call(this, root, style, constants);
class PathObject extends BasePathObject {
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for
* colouring.
* @param {!ConstantProvider} constants The renderer's constants.
* @package
* @alias Blockly.zelos.PathObject
*/
this.constants = constants;
constructor(root, style, constants) {
super(root, style, constants);
/**
* The renderer's constant provider.
* @type {!ConstantProvider}
*/
this.constants = constants;
/**
* The selected path of the block.
* @type {?SVGElement}
* @private
*/
this.svgPathSelected_ = null;
/**
* The outline paths on the block.
* @type {!Object<string, !SVGElement>}
* @private
*/
this.outlines_ = Object.create(null);
/**
* A set used to determine which outlines were used during a draw pass. The
* set is initialized with a reference to all the outlines in
* `this.outlines_`. Every time we use an outline during the draw pass, the
* reference is removed from this set.
* @type {Object<string, number>}
* @private
*/
this.remainingOutlines_ = null;
/**
* The type of block's output connection shape. This is set when a block
* with an output connection is drawn.
* @package
*/
this.outputShapeType = null;
}
/**
* The selected path of the block.
* @type {?SVGElement}
* @private
* @override
*/
this.svgPathSelected_ = null;
setPath(pathString) {
super.setPath(pathString);
if (this.svgPathSelected_) {
this.svgPathSelected_.setAttribute('d', pathString);
}
}
/**
* The outline paths on the block.
* @type {!Object<string, !SVGElement>}
* @private
* @override
*/
this.outlines_ = Object.create(null);
applyColour(block) {
super.applyColour(block);
// Set shadow stroke colour.
if (block.isShadow() && block.getParent()) {
this.svgPath.setAttribute(
'stroke', block.getParent().style.colourTertiary);
}
// Apply colour to outlines.
for (const key in this.outlines_) {
this.outlines_[key].setAttribute('fill', this.style.colourTertiary);
}
}
/**
* A set used to determine which outlines were used during a draw pass. The
* set is initialized with a reference to all the outlines in
* `this.outlines_`. Every time we use an outline during the draw pass, the
* reference is removed from this set.
* @type {Object<string, number>}
* @private
* @override
*/
this.remainingOutlines_ = null;
flipRTL() {
super.flipRTL();
// Mirror each input outline path.
for (const key in this.outlines_) {
this.outlines_[key].setAttribute('transform', 'scale(-1 1)');
}
}
/**
* The type of block's output connection shape. This is set when a block with
* an output connection is drawn.
* @override
*/
updateSelected(enable) {
this.setClass_('blocklySelected', enable);
if (enable) {
if (!this.svgPathSelected_) {
this.svgPathSelected_ =
/** @type {!SVGElement} */ (this.svgPath.cloneNode(true));
this.svgPathSelected_.setAttribute('fill', 'none');
this.svgPathSelected_.setAttribute(
'filter', 'url(#' + this.constants.selectedGlowFilterId + ')');
this.svgRoot.appendChild(this.svgPathSelected_);
}
} else {
if (this.svgPathSelected_) {
this.svgRoot.removeChild(this.svgPathSelected_);
this.svgPathSelected_ = null;
}
}
}
/**
* @override
*/
updateReplacementFade(enable) {
this.setClass_('blocklyReplaceable', enable);
if (enable) {
this.svgPath.setAttribute(
'filter', 'url(#' + this.constants.replacementGlowFilterId + ')');
} else {
this.svgPath.removeAttribute('filter');
}
}
/**
* @override
*/
updateShapeForInputHighlight(conn, enable) {
const name = conn.getParentInput().name;
const outlinePath = this.getOutlinePath_(name);
if (!outlinePath) {
return;
}
if (enable) {
outlinePath.setAttribute(
'filter', 'url(#' + this.constants.replacementGlowFilterId + ')');
} else {
outlinePath.removeAttribute('filter');
}
}
/**
* Method that's called when the drawer is about to draw the block.
* @package
*/
this.outputShapeType = null;
};
object.inherits(PathObject, BasePathObject);
/**
* @override
*/
PathObject.prototype.setPath = function(pathString) {
PathObject.superClass_.setPath.call(this, pathString);
if (this.svgPathSelected_) {
this.svgPathSelected_.setAttribute('d', pathString);
}
};
/**
* @override
*/
PathObject.prototype.applyColour = function(block) {
PathObject.superClass_.applyColour.call(this, block);
// Set shadow stroke colour.
if (block.isShadow() && block.getParent()) {
this.svgPath.setAttribute('stroke', block.getParent().style.colourTertiary);
}
// Apply colour to outlines.
for (const key in this.outlines_) {
this.outlines_[key].setAttribute('fill', this.style.colourTertiary);
}
};
/**
* @override
*/
PathObject.prototype.flipRTL = function() {
PathObject.superClass_.flipRTL.call(this);
// Mirror each input outline path.
for (const key in this.outlines_) {
this.outlines_[key].setAttribute('transform', 'scale(-1 1)');
}
};
/**
* @override
*/
PathObject.prototype.updateSelected = function(enable) {
this.setClass_('blocklySelected', enable);
if (enable) {
if (!this.svgPathSelected_) {
this.svgPathSelected_ =
/** @type {!SVGElement} */ (this.svgPath.cloneNode(true));
this.svgPathSelected_.setAttribute('fill', 'none');
this.svgPathSelected_.setAttribute(
'filter', 'url(#' + this.constants.selectedGlowFilterId + ')');
this.svgRoot.appendChild(this.svgPathSelected_);
}
} else {
if (this.svgPathSelected_) {
this.svgRoot.removeChild(this.svgPathSelected_);
this.svgPathSelected_ = null;
beginDrawing() {
this.remainingOutlines_ = Object.create(null);
for (const key in this.outlines_) {
// The value set here isn't used anywhere, we are just using the
// object as a Set data structure.
this.remainingOutlines_[key] = 1;
}
}
};
/**
* @override
*/
PathObject.prototype.updateReplacementFade = function(enable) {
this.setClass_('blocklyReplaceable', enable);
if (enable) {
this.svgPath.setAttribute(
'filter', 'url(#' + this.constants.replacementGlowFilterId + ')');
} else {
this.svgPath.removeAttribute('filter');
}
};
/**
* @override
*/
PathObject.prototype.updateShapeForInputHighlight = function(conn, enable) {
const name = conn.getParentInput().name;
const outlinePath = this.getOutlinePath_(name);
if (!outlinePath) {
return;
}
if (enable) {
outlinePath.setAttribute(
'filter', 'url(#' + this.constants.replacementGlowFilterId + ')');
} else {
outlinePath.removeAttribute('filter');
}
};
/**
* Method that's called when the drawer is about to draw the block.
* @package
*/
PathObject.prototype.beginDrawing = function() {
this.remainingOutlines_ = Object.create(null);
for (const key in this.outlines_) {
// The value set here isn't used anywhere, we are just using the
// object as a Set data structure.
this.remainingOutlines_[key] = 1;
}
};
/**
* Method that's called when the drawer is done drawing.
* @package
*/
PathObject.prototype.endDrawing = function() {
// Go through all remaining outlines that were not used this draw pass, and
// remove them.
if (this.remainingOutlines_) {
for (const key in this.remainingOutlines_) {
this.removeOutlinePath_(key);
/**
* Method that's called when the drawer is done drawing.
* @package
*/
endDrawing() {
// Go through all remaining outlines that were not used this draw pass, and
// remove them.
if (this.remainingOutlines_) {
for (const key in this.remainingOutlines_) {
this.removeOutlinePath_(key);
}
}
this.remainingOutlines_ = null;
}
this.remainingOutlines_ = null;
};
/**
* Set the path generated by the renderer for an outline path on the respective
* outline path SVG element.
* @param {string} name The input name.
* @param {string} pathString The path.
* @package
*/
PathObject.prototype.setOutlinePath = function(name, pathString) {
const outline = this.getOutlinePath_(name);
outline.setAttribute('d', pathString);
outline.setAttribute('fill', this.style.colourTertiary);
};
/**
* Create's an outline path for the specified input.
* @param {string} name The input name.
* @return {!SVGElement} The SVG outline path.
* @private
*/
PathObject.prototype.getOutlinePath_ = function(name) {
if (!this.outlines_[name]) {
this.outlines_[name] = dom.createSvgElement(
Svg.PATH, {
'class': 'blocklyOutlinePath',
// IE doesn't like paths without the data definition, set empty
// default
'd': '',
},
this.svgRoot);
/**
* Set the path generated by the renderer for an outline path on the
* respective outline path SVG element.
* @param {string} name The input name.
* @param {string} pathString The path.
* @package
*/
setOutlinePath(name, pathString) {
const outline = this.getOutlinePath_(name);
outline.setAttribute('d', pathString);
outline.setAttribute('fill', this.style.colourTertiary);
}
if (this.remainingOutlines_) {
delete this.remainingOutlines_[name];
}
return this.outlines_[name];
};
/**
* Remove an outline path that is associated with the specified input.
* @param {string} name The input name.
* @private
*/
PathObject.prototype.removeOutlinePath_ = function(name) {
this.outlines_[name].parentNode.removeChild(this.outlines_[name]);
delete this.outlines_[name];
};
/**
* Create's an outline path for the specified input.
* @param {string} name The input name.
* @return {!SVGElement} The SVG outline path.
* @private
*/
getOutlinePath_(name) {
if (!this.outlines_[name]) {
this.outlines_[name] = dom.createSvgElement(
Svg.PATH, {
'class': 'blocklyOutlinePath',
// IE doesn't like paths without the data definition, set empty
// default
'd': '',
},
this.svgRoot);
}
if (this.remainingOutlines_) {
delete this.remainingOutlines_[name];
}
return this.outlines_[name];
}
/**
* Remove an outline path that is associated with the specified input.
* @param {string} name The input name.
* @private
*/
removeOutlinePath_(name) {
this.outlines_[name].parentNode.removeChild(this.outlines_[name]);
delete this.outlines_[name];
}
}
exports.PathObject = PathObject;

View File

@@ -16,7 +16,6 @@
goog.module('Blockly.zelos.Renderer');
const blockRendering = goog.require('Blockly.blockRendering');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {ConnectionType} = goog.require('Blockly.ConnectionType');
@@ -39,109 +38,109 @@ const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
/**
* The zelos renderer.
* @param {string} name The renderer name.
* @package
* @constructor
* @extends {BaseRenderer}
* @alias Blockly.zelos.Renderer
*/
const Renderer = function(name) {
Renderer.superClass_.constructor.call(this, name);
};
object.inherits(Renderer, BaseRenderer);
/**
* Create a new instance of the renderer's constant provider.
* @return {!ConstantProvider} The constant provider.
* @protected
* @override
*/
Renderer.prototype.makeConstants_ = function() {
return new ConstantProvider();
};
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
Renderer.prototype.makeRenderInfo_ = function(block) {
return new RenderInfo(this, block);
};
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all
* information needed to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
Renderer.prototype.makeDrawer_ = function(block, info) {
return new Drawer(
block,
/** @type {!RenderInfo} */ (info));
};
/**
* Create a new instance of the renderer's cursor drawer.
* @param {!WorkspaceSvg} workspace The workspace the cursor belongs to.
* @param {!Marker} marker The marker.
* @return {!MarkerSvg} The object in charge of drawing
* the marker.
* @package
* @override
*/
Renderer.prototype.makeMarkerDrawer = function(workspace, marker) {
return new MarkerSvg(workspace, this.getConstants(), marker);
};
/**
* Create a new instance of a renderer path object.
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for
* colouring.
* @return {!PathObject} The renderer path object.
* @package
* @override
*/
Renderer.prototype.makePathObject = function(root, style) {
return new PathObject(
root, style,
/** @type {!ConstantProvider} */ (this.getConstants()));
};
/**
* @override
*/
Renderer.prototype.shouldHighlightConnection = function(conn) {
return conn.type !== ConnectionType.INPUT_VALUE &&
conn.type !== ConnectionType.OUTPUT_VALUE;
};
/**
* @override
*/
Renderer.prototype.getConnectionPreviewMethod = function(
closest, local, topBlock) {
if (local.type === ConnectionType.OUTPUT_VALUE) {
if (!closest.isConnected()) {
return InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE;
}
// TODO: Returning this is a total hack, because we don't want to show
// a replacement fade, we want to show an outline affect.
// Sadly zelos does not support showing an outline around filled
// inputs, so we have to pretend like the connected block is getting
// replaced.
return InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE;
class Renderer extends BaseRenderer {
/**
* @param {string} name The renderer name.
* @package
* @alias Blockly.zelos.Renderer
*/
constructor(name) {
super(name);
}
return Renderer.superClass_.getConnectionPreviewMethod(
closest, local, topBlock);
};
/**
* Create a new instance of the renderer's constant provider.
* @return {!ConstantProvider} The constant provider.
* @protected
* @override
*/
makeConstants_() {
return new ConstantProvider();
}
/**
* Create a new instance of the renderer's render info object.
* @param {!BlockSvg} block The block to measure.
* @return {!RenderInfo} The render info object.
* @protected
* @override
*/
makeRenderInfo_(block) {
return new RenderInfo(this, block);
}
/**
* Create a new instance of the renderer's drawer.
* @param {!BlockSvg} block The block to render.
* @param {!BaseRenderInfo} info An object containing all
* information needed to render this block.
* @return {!Drawer} The drawer.
* @protected
* @override
*/
makeDrawer_(block, info) {
return new Drawer(
block,
/** @type {!RenderInfo} */ (info));
}
/**
* Create a new instance of the renderer's cursor drawer.
* @param {!WorkspaceSvg} workspace The workspace the cursor belongs to.
* @param {!Marker} marker The marker.
* @return {!MarkerSvg} The object in charge of drawing
* the marker.
* @package
* @override
*/
makeMarkerDrawer(workspace, marker) {
return new MarkerSvg(workspace, this.getConstants(), marker);
}
/**
* Create a new instance of a renderer path object.
* @param {!SVGElement} root The root SVG element.
* @param {!Theme.BlockStyle} style The style object to use for
* colouring.
* @return {!PathObject} The renderer path object.
* @package
* @override
*/
makePathObject(root, style) {
return new PathObject(
root, style,
/** @type {!ConstantProvider} */ (this.getConstants()));
}
/**
* @override
*/
shouldHighlightConnection(conn) {
return conn.type !== ConnectionType.INPUT_VALUE &&
conn.type !== ConnectionType.OUTPUT_VALUE;
}
/**
* @override
*/
getConnectionPreviewMethod(closest, local, topBlock) {
if (local.type === ConnectionType.OUTPUT_VALUE) {
if (!closest.isConnected()) {
return InsertionMarkerManager.PREVIEW_TYPE.INPUT_OUTLINE;
}
// TODO: Returning this is a total hack, because we don't want to show
// a replacement fade, we want to show an outline affect.
// Sadly zelos does not support showing an outline around filled
// inputs, so we have to pretend like the connected block is getting
// replaced.
return InsertionMarkerManager.PREVIEW_TYPE.REPLACEMENT_FADE;
}
return super.getConnectionPreviewMethod(closest, local, topBlock);
}
}
blockRendering.register('zelos', Renderer);

View File

@@ -52,8 +52,8 @@
"./core/renderers/geras/measurables/statement_input.js",
"./core/renderers/geras/path_object.js",
"./core/renderers/geras/renderer.js",
"./core/renderers/geras/measurables/inline_input.js",
"./core/renderers/geras/info.js",
"./core/renderers/geras/measurables/inline_input.js",
"./core/renderers/geras/highlight_constants.js",
"./core/renderers/geras/highlighter.js",
"./core/renderers/geras/drawer.js",

View File

@@ -150,16 +150,16 @@ goog.addDependency('../../core/renderers/common/info.js', ['Blockly.blockRenderi
goog.addDependency('../../core/renderers/common/marker_svg.js', ['Blockly.blockRendering.MarkerSvg'], ['Blockly.ASTNode', 'Blockly.ConnectionType', 'Blockly.Events.MarkerMove', 'Blockly.Events.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/common/path_object.js', ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.IPathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/common/renderer.js', ['Blockly.blockRendering.Renderer'], ['Blockly.Connection', 'Blockly.ConnectionType', 'Blockly.IRegistrable', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.MarkerSvg', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.debug', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/constants.js', ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.blockRendering.debug', 'Blockly.geras.Highlighter', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/constants.js', ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.blockRendering.debug', 'Blockly.geras.Highlighter', 'Blockly.geras.InlineInput', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/geras.js', ['Blockly.geras'], ['Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.Highlighter', 'Blockly.geras.InlineInput', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.geras.Renderer', 'Blockly.geras.StatementInput'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/highlight_constants.js', ['Blockly.geras.HighlightConstantProvider'], ['Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras.RenderInfo'], ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.inputTypes', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/measurables/inline_input.js', ['Blockly.geras.InlineInput'], ['Blockly.blockRendering.InlineInput', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/measurables/statement_input.js', ['Blockly.geras.StatementInput'], ['Blockly.blockRendering.StatementInput', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.geras.InlineInput', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras.RenderInfo'], ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.inputTypes'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/measurables/inline_input.js', ['Blockly.geras.InlineInput'], ['Blockly.blockRendering.InlineInput'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/measurables/statement_input.js', ['Blockly.geras.StatementInput'], ['Blockly.blockRendering.StatementInput'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/path_object.js', ['Blockly.geras.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/renderer.js', ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/geras/renderer.js', ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/measurables/base.js', ['Blockly.blockRendering.Measurable'], ['Blockly.blockRendering.Types'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/measurables/bottom_row.js', ['Blockly.blockRendering.BottomRow'], ['Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/measurables/connection.js', ['Blockly.blockRendering.Connection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
@@ -182,24 +182,24 @@ goog.addDependency('../../core/renderers/measurables/square_corner.js', ['Blockl
goog.addDependency('../../core/renderers/measurables/statement_input.js', ['Blockly.blockRendering.StatementInput'], ['Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/measurables/top_row.js', ['Blockly.blockRendering.TopRow'], ['Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/measurables/types.js', ['Blockly.blockRendering.Types'], [], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/constants.js', ['Blockly.minimalist.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/drawer.js', ['Blockly.minimalist.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/info.js', ['Blockly.minimalist.RenderInfo'], ['Blockly.blockRendering.RenderInfo', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/constants.js', ['Blockly.minimalist.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/drawer.js', ['Blockly.minimalist.Drawer'], ['Blockly.blockRendering.Drawer'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/info.js', ['Blockly.minimalist.RenderInfo'], ['Blockly.blockRendering.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/minimalist.js', ['Blockly.minimalist'], ['Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.minimalist.Renderer'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/renderer.js', ['Blockly.minimalist.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/thrasos/info.js', ['Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/thrasos/renderer.js', ['Blockly.thrasos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.thrasos.RenderInfo', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/minimalist/renderer.js', ['Blockly.minimalist.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/thrasos/info.js', ['Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/thrasos/renderer.js', ['Blockly.thrasos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.thrasos.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/thrasos/thrasos.js', ['Blockly.thrasos'], ['Blockly.thrasos.RenderInfo', 'Blockly.thrasos.Renderer'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/constants.js', ['Blockly.zelos.ConstantProvider'], ['Blockly.ConnectionType', 'Blockly.blockRendering.ConstantProvider', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/drawer.js', ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.blockRendering.debug', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/info.js', ['Blockly.zelos.RenderInfo'], ['Blockly.FieldImage', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Input', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.inputTypes', 'Blockly.utils.object', 'Blockly.zelos.BottomRow', 'Blockly.zelos.RightConnectionShape', 'Blockly.zelos.StatementInput', 'Blockly.zelos.TopRow'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/marker_svg.js', ['Blockly.zelos.MarkerSvg'], ['Blockly.blockRendering.MarkerSvg', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/bottom_row.js', ['Blockly.zelos.BottomRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/inputs.js', ['Blockly.zelos.StatementInput'], ['Blockly.blockRendering.StatementInput', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/row_elements.js', ['Blockly.zelos.RightConnectionShape'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/top_row.js', ['Blockly.zelos.TopRow'], ['Blockly.blockRendering.TopRow', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.ConnectionType', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/constants.js', ['Blockly.zelos.ConstantProvider'], ['Blockly.ConnectionType', 'Blockly.blockRendering.ConstantProvider', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/drawer.js', ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.blockRendering.debug', 'Blockly.utils.svgPaths'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/info.js', ['Blockly.zelos.RenderInfo'], ['Blockly.FieldImage', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Input', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.inputTypes', 'Blockly.zelos.BottomRow', 'Blockly.zelos.RightConnectionShape', 'Blockly.zelos.StatementInput', 'Blockly.zelos.TopRow'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/marker_svg.js', ['Blockly.zelos.MarkerSvg'], ['Blockly.blockRendering.MarkerSvg', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/bottom_row.js', ['Blockly.zelos.BottomRow'], ['Blockly.blockRendering.BottomRow'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/inputs.js', ['Blockly.zelos.StatementInput'], ['Blockly.blockRendering.StatementInput'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/row_elements.js', ['Blockly.zelos.RightConnectionShape'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/measurables/top_row.js', ['Blockly.zelos.TopRow'], ['Blockly.blockRendering.TopRow'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.ConnectionType', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/renderers/zelos/zelos.js', ['Blockly.zelos'], ['Blockly.zelos.BottomRow', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo', 'Blockly.zelos.Renderer', 'Blockly.zelos.RightConnectionShape', 'Blockly.zelos.StatementInput', 'Blockly.zelos.TopRow'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar'], ['Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgMath'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/scrollbar_pair.js', ['Blockly.ScrollbarPair'], ['Blockly.Events.utils', 'Blockly.Scrollbar', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});