mirror of
https://github.com/google/blockly.git
synced 2026-01-08 01:20:12 +01:00
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:
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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'});
|
||||
|
||||
Reference in New Issue
Block a user