refactor: convert renderer measurables to es6 classes (#5899)

* chore: use casts to narrow types in renderers

* chore: add @struct and type information on common measurables

* refactor: update some renderer measurables to es6 classes

* refactor: convert many measurables to es6 classes

* chore: format

* chore: rebuild
This commit is contained in:
Rachel Fenichel
2022-02-01 15:43:11 -08:00
committed by GitHub
parent 2b73dd550e
commit 97c19be612
29 changed files with 734 additions and 575 deletions

View File

@@ -22,6 +22,8 @@ const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {ExternalValueInput} = goog.requireType('Blockly.blockRendering.ExternalValueInput');
/* eslint-disable-next-line no-unused-vars */
const {Field} = goog.requireType('Blockly.blockRendering.Field');
/* eslint-disable-next-line no-unused-vars */
const {Icon} = goog.requireType('Blockly.blockRendering.Icon');
@@ -175,7 +177,8 @@ Drawer.prototype.drawJaggedEdge_ = function(row) {
* @protected
*/
Drawer.prototype.drawValueInput_ = function(row) {
const input = row.getLastInput();
const input =
/** @type {ExternalValueInput|InlineInput} */ (row.getLastInput());
this.positionExternalValueConnection_(row);
const pathDown = (typeof input.shape.pathDown === 'function') ?

View File

@@ -90,7 +90,7 @@ const RenderInfo = function(renderer, block) {
null :
new OutputConnection(
this.constants_,
/** @type {RenderedConnection} */ (block.outputConnection));
/** @type {!RenderedConnection} */ (block.outputConnection));
/**
* Whether the block should be rendered as a single line, either because it's
@@ -285,7 +285,7 @@ RenderInfo.prototype.populateTopRow_ = function() {
this.topRow.hasPreviousConnection = true;
this.topRow.connection = new PreviousConnection(
this.constants_,
/** @type {RenderedConnection} */
/** @type {!RenderedConnection} */
(this.block_.previousConnection));
this.topRow.elements.push(this.topRow.connection);
}
@@ -338,7 +338,7 @@ RenderInfo.prototype.populateBottomRow_ = function() {
if (this.bottomRow.hasNextConnection) {
this.bottomRow.connection = new NextConnection(
this.constants_,
/** @type {RenderedConnection} */ (this.block_.nextConnection));
/** @type {!RenderedConnection} */ (this.block_.nextConnection));
this.bottomRow.elements.push(this.bottomRow.connection);
}
@@ -695,17 +695,20 @@ RenderInfo.prototype.getElemCenterline_ = function(row, elem) {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
const bottomRow = /** @type {!BottomRow} */ (row);
const baseline =
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
const topRow = /** @type {!TopRow} */ (row);
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
return topRow.capline - elem.height / 2;
}
return row.capline + elem.height / 2;
return topRow.capline + elem.height / 2;
}
return row.yPos + row.height / 2;
};

View File

@@ -148,7 +148,7 @@ class Highlighter {
* @package
*/
drawValueInput(row) {
const input = row.getLastInput();
const input = /** @type {!InlineInput}} */ (row.getLastInput());
if (this.RTL_) {
const belowTabHeight = row.height - input.connectionHeight;

View File

@@ -19,6 +19,8 @@ goog.module('Blockly.geras.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
const {BottomRow} = goog.requireType('Blockly.blockRendering.BottomRow');
const {ExternalValueInput} = goog.require('Blockly.blockRendering.ExternalValueInput');
/* eslint-disable-next-line no-unused-vars */
const {Field} = goog.requireType('Blockly.blockRendering.Field');
@@ -30,6 +32,8 @@ const {RenderInfo: BaseRenderInfo} = goog.require('Blockly.blockRendering.Render
/* eslint-disable-next-line no-unused-vars */
const {Renderer} = goog.requireType('Blockly.geras.Renderer');
const {StatementInput} = goog.require('Blockly.geras.StatementInput');
/* eslint-disable-next-line no-unused-vars */
const {TopRow} = goog.requireType('Blockly.blockRendering.TopRow');
const {Types} = goog.require('Blockly.blockRendering.Types');
const {inputTypes} = goog.require('Blockly.inputTypes');
@@ -333,17 +337,20 @@ class RenderInfo extends BaseRenderInfo {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
const bottomRow = /** @type {!BottomRow} */ (row);
const baseline =
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
const topRow = /** @type {!TopRow} */ (row);
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
return topRow.capline - elem.height / 2;
}
return row.capline + elem.height / 2;
return topRow.capline + elem.height / 2;
}
let result = row.yPos;

View File

@@ -32,11 +32,19 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
* @alias Blockly.blockRendering.Measurable
*/
const Measurable = function(constants) {
/** @type {number} */
this.width = 0;
/** @type {number} */
this.height = 0;
/** @type {number} */
this.type = Types.NONE;
/** @type {number} */
this.xPos = 0;
/** @type {number} */
this.centerline = 0;
/**
@@ -46,6 +54,7 @@ const Measurable = function(constants) {
*/
this.constants_ = constants;
/** @type {number} */
this.notchOffset = this.constants_.NOTCH_OFFSET_LEFT;
};

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.BottomRow');
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 */
@@ -32,104 +31,108 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
* a block as well as spacing information for the bottom row.
* Elements in a bottom row can consist of corners, spacers and next
* connections.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {Row}
* @alias Blockly.blockRendering.BottomRow
* @struct
*/
const BottomRow = function(constants) {
BottomRow.superClass_.constructor.call(this, constants);
this.type |= Types.BOTTOM_ROW;
class BottomRow extends Row {
/**
* Whether this row has a next connection.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @type {boolean}
* @alias Blockly.blockRendering.BottomRow
*/
this.hasNextConnection = false;
constructor(constants) {
super(constants);
this.type |= Types.BOTTOM_ROW;
/**
* Whether this row has a next connection.
* @package
* @type {boolean}
*/
this.hasNextConnection = false;
/**
* The next connection on the row, if any.
* @package
* @type {NextConnection}
*/
this.connection = null;
/**
* The amount that the bottom of the block extends below the horizontal
* edge, e.g. because of a next connection. Must be non-negative (see
* #2820).
* @package
* @type {number}
*/
this.descenderHeight = 0;
/**
* The Y position of the bottom edge of the block, relative to the origin
* of the block rendering.
* @type {number}
*/
this.baseline = 0;
}
/**
* The next connection on the row, if any.
* @package
* @type {NextConnection}
* Returns whether or not the bottom row has a left square corner.
* @param {!BlockSvg} block The block whose bottom row this represents.
* @return {boolean} Whether or not the bottom row has a left square corner.
*/
this.connection = null;
hasLeftSquareCorner(block) {
return !!block.outputConnection || !!block.getNextBlock();
}
/**
* The amount that the bottom of the block extends below the horizontal edge,
* e.g. because of a next connection. Must be non-negative (see #2820).
* @package
* @type {number}
* Returns whether or not the bottom row has a right square corner.
* @param {!BlockSvg} _block The block whose bottom row this represents.
* @return {boolean} Whether or not the bottom row has a right square corner.
*/
this.descenderHeight = 0;
hasRightSquareCorner(_block) {
return true;
}
/**
* The Y position of the bottom edge of the block, relative to the origin
* of the block rendering.
* @type {number}
* @override
*/
this.baseline = 0;
};
object.inherits(BottomRow, Row);
/**
* Returns whether or not the bottom row has a left square corner.
* @param {!BlockSvg} block The block whose bottom row this represents.
* @return {boolean} Whether or not the bottom row has a left square corner.
*/
BottomRow.prototype.hasLeftSquareCorner = function(block) {
return !!block.outputConnection || !!block.getNextBlock();
};
/**
* Returns whether or not the bottom row has a right square corner.
* @param {!BlockSvg} _block The block whose bottom row this represents.
* @return {boolean} Whether or not the bottom row has a right square corner.
*/
BottomRow.prototype.hasRightSquareCorner = function(_block) {
return true;
};
/**
* @override
*/
BottomRow.prototype.measure = function() {
let height = 0;
let width = 0;
let descenderHeight = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
width += elem.width;
if (!(Types.isSpacer(elem))) {
// Note: this assumes that next connections have *only* descenderHeight,
// with no height above the baseline.
if (Types.isNextConnection(elem)) {
descenderHeight = Math.max(descenderHeight, elem.height);
} else {
height = Math.max(height, elem.height);
measure() {
let height = 0;
let width = 0;
let descenderHeight = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
width += elem.width;
if (!(Types.isSpacer(elem))) {
// Note: this assumes that next connections have *only* descenderHeight,
// with no height above the baseline.
if (Types.isNextConnection(elem)) {
descenderHeight = Math.max(descenderHeight, elem.height);
} else {
height = Math.max(height, elem.height);
}
}
}
this.width = Math.max(this.minWidth, width);
this.height = Math.max(this.minHeight, height) + descenderHeight;
this.descenderHeight = descenderHeight;
this.widthWithConnectedBlocks = this.width;
}
this.width = Math.max(this.minWidth, width);
this.height = Math.max(this.minHeight, height) + descenderHeight;
this.descenderHeight = descenderHeight;
this.widthWithConnectedBlocks = this.width;
};
/**
* @override
*/
BottomRow.prototype.startsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
startsWithElemSpacer() {
return false;
}
/**
* @override
*/
BottomRow.prototype.endsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
endsWithElemSpacer() {
return false;
}
}
exports.BottomRow = BottomRow;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.Connection');
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');
@@ -28,22 +27,30 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* The base class to represent a connection and the space that it takes up on
* the block.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.blockRendering.Connection
*/
const Connection = function(constants, connectionModel) {
Connection.superClass_.constructor.call(this, constants);
this.connectionModel = connectionModel;
this.shape = this.constants_.shapeFor(connectionModel);
this.isDynamicShape = !!this.shape['isDynamic'];
this.type |= Types.CONNECTION;
};
object.inherits(Connection, Measurable);
class Connection extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @alias Blockly.blockRendering.Connection
*/
constructor(constants, connectionModel) {
super(constants);
/** @type {!RenderedConnection} */
this.connectionModel = connectionModel;
/** @type {!Object} */
this.shape = this.constants_.shapeFor(connectionModel);
/** @type {boolean} */
this.isDynamicShape = !!this.shape['isDynamic'];
this.type |= Types.CONNECTION;
}
}
exports.Connection = Connection;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.ExternalValueInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InputConnection} = goog.require('Blockly.blockRendering.InputConnection');
@@ -28,30 +27,44 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space an external value input
* takes up during rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The external value input to measure and store
* information for.
* @package
* @constructor
* @struct
* @extends {InputConnection}
* @alias Blockly.blockRendering.ExternalValueInput
*/
const ExternalValueInput = function(constants, input) {
ExternalValueInput.superClass_.constructor.call(this, constants, input);
this.type |= Types.EXTERNAL_VALUE_INPUT;
if (!this.connectedBlock) {
this.height = this.shape.height;
} else {
this.height = this.connectedBlockHeight -
this.constants_.TAB_OFFSET_FROM_TOP - this.constants_.MEDIUM_PADDING;
}
this.width = this.shape.width + this.constants_.EXTERNAL_VALUE_INPUT_PADDING;
class ExternalValueInput extends InputConnection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The external value input to measure and store
* information for.
* @package
* @alias Blockly.blockRendering.ExternalValueInput
*/
constructor(constants, input) {
super(constants, input);
this.type |= Types.EXTERNAL_VALUE_INPUT;
this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP;
this.connectionHeight = this.shape.height;
this.connectionWidth = this.shape.width;
};
object.inherits(ExternalValueInput, InputConnection);
/** @type {number} */
this.height = 0;
if (!this.connectedBlock) {
this.height = this.shape.height;
} else {
this.height = this.connectedBlockHeight -
this.constants_.TAB_OFFSET_FROM_TOP - this.constants_.MEDIUM_PADDING;
}
/** @type {number} */
this.width =
this.shape.width + this.constants_.EXTERNAL_VALUE_INPUT_PADDING;
/** @type {number} */
this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP;
/** @type {number} */
this.connectionHeight = this.shape.height;
/** @type {number} */
this.connectionWidth = this.shape.width;
}
}
exports.ExternalValueInput = ExternalValueInput;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.Field');
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 */
@@ -30,27 +29,43 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a field takes up during
* rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!BlocklyField} field The field to measure and store information for.
* @param {!Input} parentInput The parent input for the field.
* @package
* @constructor
* @struct
* @extends {Measurable}
* @alias Blockly.blockRendering.Field
*/
const Field = function(constants, field, parentInput) {
Field.superClass_.constructor.call(this, constants);
this.field = field;
this.isEditable = field.EDITABLE;
this.flipRtl = field.getFlipRtl();
this.type |= Types.FIELD;
class Field extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!BlocklyField} field The field to measure and store information
* for.
* @param {!Input} parentInput The parent input for the field.
* @package
* @alias Blockly.blockRendering.Field
*/
constructor(constants, field, parentInput) {
super(constants);
const size = this.field.getSize();
this.height = size.height;
this.width = size.width;
this.parentInput = parentInput;
};
object.inherits(Field, Measurable);
/** @type {!BlocklyField} */
this.field = field;
/** @type {boolean} */
this.isEditable = field.EDITABLE;
/** @type {boolean} */
this.flipRtl = field.getFlipRtl();
this.type |= Types.FIELD;
const size = this.field.getSize();
/** @type {number} */
this.height = size.height;
/** @type {number} */
this.width = size.width;
/** @type {!Input} */
this.parentInput = parentInput;
}
}
exports.Field = Field;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.Hat');
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,26 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a hat takes up during
* rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @struct
* @extends {Measurable}
* @alias Blockly.blockRendering.Hat
*/
const Hat = function(constants) {
Hat.superClass_.constructor.call(this, constants);
this.type |= Types.HAT;
this.height = this.constants_.START_HAT.height;
this.width = this.constants_.START_HAT.width;
this.ascenderHeight = this.height;
};
object.inherits(Hat, Measurable);
class Hat extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.blockRendering.Hat
*/
constructor(constants) {
super(constants);
this.type |= Types.HAT;
this.height = this.constants_.START_HAT.height;
this.width = this.constants_.START_HAT.width;
/** @type {number} */
this.ascenderHeight = this.height;
}
}
exports.Hat = Hat;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.Icon');
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 */
@@ -28,24 +27,33 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space an icon takes up during
* rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!BlocklyIcon} icon The icon to measure and store information for.
* @package
* @constructor
* @extends {Measurable}
* @struct
* @alias Blockly.blockRendering.Icon
*/
const Icon = function(constants, icon) {
Icon.superClass_.constructor.call(this, constants);
this.icon = icon;
this.isVisible = icon.isVisible();
this.type |= Types.ICON;
class Icon extends Measurable {
/**
* An object containing information about the space an icon takes up during
* rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!BlocklyIcon} icon The icon to measure and store information for.
* @package
* @alias Blockly.blockRendering.Icon
*/
constructor(constants, icon) {
super(constants);
const size = icon.getCorrectedSize();
this.height = size.height;
this.width = size.width;
};
object.inherits(Icon, Measurable);
/** @type {!BlocklyIcon} */
this.icon = icon;
/** @type {boolean} */
this.isVisible = icon.isVisible();
this.type |= Types.ICON;
const size = icon.getCorrectedSize();
this.height = size.height;
this.width = size.width;
}
}
exports.Icon = Icon;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.InRowSpacer');
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,23 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about a spacer between two elements on a
* row.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {number} width The width of the spacer.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.blockRendering.InRowSpacer
* @struct
*/
const InRowSpacer = function(constants, width) {
InRowSpacer.superClass_.constructor.call(this, constants);
this.type |= Types.SPACER | Types.IN_ROW_SPACER;
this.width = width;
this.height = this.constants_.SPACER_DEFAULT_HEIGHT;
};
object.inherits(InRowSpacer, Measurable);
class InRowSpacer extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {number} width The width of the spacer.
* @package
* @alias Blockly.blockRendering.InRowSpacer
*/
constructor(constants, width) {
super(constants);
this.type |= Types.SPACER | Types.IN_ROW_SPACER;
this.width = width;
this.height = this.constants_.SPACER_DEFAULT_HEIGHT;
}
}
exports.InRowSpacer = InRowSpacer;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.InlineInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InputConnection} = goog.require('Blockly.blockRendering.InputConnection');
@@ -28,43 +27,54 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* 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
* @extends {InputConnection}
* @alias Blockly.blockRendering.InlineInput
* @struct
*/
const InlineInput = function(constants, input) {
InlineInput.superClass_.constructor.call(this, constants, input);
this.type |= Types.INLINE_INPUT;
class InlineInput extends InputConnection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The inline input to measure and store
* information for.
* @package
* @alias Blockly.blockRendering.InlineInput
*/
constructor(constants, input) {
super(constants, input);
this.type |= Types.INLINE_INPUT;
if (!this.connectedBlock) {
this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT;
this.width = this.constants_.EMPTY_INLINE_INPUT_PADDING;
} else {
// 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.connectedBlockWidth;
this.height = this.connectedBlockHeight;
}
if (!this.connectedBlock) {
this.height = this.constants_.EMPTY_INLINE_INPUT_HEIGHT;
this.width = this.constants_.EMPTY_INLINE_INPUT_PADDING;
} else {
// 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.connectedBlockWidth;
this.height = this.connectedBlockHeight;
}
this.connectionHeight =
!this.isDynamicShape ? this.shape.height : this.shape.height(this.height);
this.connectionWidth =
!this.isDynamicShape ? this.shape.width : this.shape.width(this.height);
if (!this.connectedBlock) {
this.width += this.connectionWidth * (this.isDynamicShape ? 2 : 1);
/** @type {number} */
this.connectionHeight = !this.isDynamicShape ?
this.shape.height :
this.shape.height(this.height);
/** @type {number} */
this.connectionWidth =
!this.isDynamicShape ? this.shape.width : this.shape.width(this.height);
if (!this.connectedBlock) {
this.width += this.connectionWidth * (this.isDynamicShape ? 2 : 1);
}
/** @type {number} */
this.connectionOffsetY = this.isDynamicShape ?
this.shape.connectionOffsetY(this.connectionHeight) :
this.constants_.TAB_OFFSET_FROM_TOP;
/** @type {number} */
this.connectionOffsetX = this.isDynamicShape ?
this.shape.connectionOffsetX(this.connectionWidth) :
0;
}
this.connectionOffsetY = this.isDynamicShape ?
this.shape.connectionOffsetY(this.connectionHeight) :
this.constants_.TAB_OFFSET_FROM_TOP;
this.connectionOffsetX = this.isDynamicShape ?
this.shape.connectionOffsetX(this.connectionWidth) :
0;
};
object.inherits(InlineInput, InputConnection);
}
exports.InlineInput = InlineInput;

View File

@@ -14,49 +14,62 @@
*/
goog.module('Blockly.blockRendering.InputConnection');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
const {Connection} = goog.require('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
/* eslint-disable-next-line no-unused-vars */
const {Input} = goog.requireType('Blockly.Input');
/* eslint-disable-next-line no-unused-vars */
const {RenderedConnection} = goog.requireType('Blockly.RenderedConnection');
const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* The base class to represent an input that takes up space on a block
* during rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The input to measure and store information for.
* @package
* @constructor
* @extends {Connection}
* @alias Blockly.blockRendering.InputConnection
*/
const InputConnection = function(constants, input) {
InputConnection.superClass_.constructor.call(
this, constants, input.connection);
class InputConnection extends Connection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The input to measure and store information for.
* @alias Blockly.blockRendering.InputConnection
*/
constructor(constants, input) {
super(constants, /** @type {!RenderedConnection} */ (input.connection));
this.type |= Types.INPUT;
this.input = input;
this.align = input.align;
this.connectedBlock = input.connection && input.connection.targetBlock() ?
input.connection.targetBlock() :
null;
this.type |= Types.INPUT;
if (this.connectedBlock) {
const bBox = this.connectedBlock.getHeightWidth();
this.connectedBlockWidth = bBox.width;
this.connectedBlockHeight = bBox.height;
} else {
this.connectedBlockWidth = 0;
this.connectedBlockHeight = 0;
/** @type {!Input} */
this.input = input;
/** @type {number} */
this.align = input.align;
/** @type {BlockSvg} */
this.connectedBlock = input.connection && input.connection.targetBlock() ?
/** @type {BlockSvg} */ (input.connection.targetBlock()) :
null;
if (this.connectedBlock) {
const bBox = this.connectedBlock.getHeightWidth();
this.connectedBlockWidth = bBox.width;
this.connectedBlockHeight = bBox.height;
} else {
this.connectedBlockWidth = 0;
this.connectedBlockHeight = 0;
}
/** @type {number} */
this.connectionOffsetX = 0;
/** @type {number} */
this.connectionOffsetY = 0;
}
this.connectionOffsetX = 0;
this.connectionOffsetY = 0;
};
object.inherits(InputConnection, Connection);
}
exports.InputConnection = InputConnection;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.InputRow');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {Row} = goog.require('Blockly.blockRendering.Row');
@@ -25,59 +24,62 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about a row that holds one or more inputs.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {Row}
* @alias Blockly.blockRendering.InputRow
* @struct
*/
const InputRow = function(constants) {
InputRow.superClass_.constructor.call(this, constants);
this.type |= Types.INPUT_ROW;
class InputRow extends Row {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.blockRendering.InputRow
*/
constructor(constants) {
super(constants);
this.type |= Types.INPUT_ROW;
/**
* The total width of all blocks connected to this row.
* @type {number}
* @package
*/
this.connectedBlockWidths = 0;
}
/**
* The total width of all blocks connected to this row.
* @type {number}
* Inspect all subcomponents and populate all size properties on the row.
* @package
*/
this.connectedBlockWidths = 0;
};
object.inherits(InputRow, Row);
/**
* Inspect all subcomponents and populate all size properties on the row.
* @package
*/
InputRow.prototype.measure = function() {
this.width = this.minWidth;
this.height = this.minHeight;
let connectedBlockWidths = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
this.width += elem.width;
if (Types.isInput(elem)) {
if (Types.isStatementInput(elem)) {
connectedBlockWidths += elem.connectedBlockWidth;
} else if (
Types.isExternalInput(elem) && elem.connectedBlockWidth !== 0) {
connectedBlockWidths +=
(elem.connectedBlockWidth - elem.connectionWidth);
measure() {
this.width = this.minWidth;
this.height = this.minHeight;
let connectedBlockWidths = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
this.width += elem.width;
if (Types.isInput(elem)) {
if (Types.isStatementInput(elem)) {
connectedBlockWidths += elem.connectedBlockWidth;
} else if (
Types.isExternalInput(elem) && elem.connectedBlockWidth !== 0) {
connectedBlockWidths +=
(elem.connectedBlockWidth - elem.connectionWidth);
}
}
if (!(Types.isSpacer(elem))) {
this.height = Math.max(this.height, elem.height);
}
}
if (!(Types.isSpacer(elem))) {
this.height = Math.max(this.height, elem.height);
}
this.connectedBlockWidths = connectedBlockWidths;
this.widthWithConnectedBlocks = this.width + connectedBlockWidths;
}
this.connectedBlockWidths = connectedBlockWidths;
this.widthWithConnectedBlocks = this.width + connectedBlockWidths;
};
/**
* @override
*/
InputRow.prototype.endsWithElemSpacer = function() {
return !this.hasExternalInput && !this.hasStatement;
};
/**
* @override
*/
endsWithElemSpacer() {
return !this.hasExternalInput && !this.hasStatement;
}
}
exports.InputRow = InputRow;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.JaggedEdge');
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,19 +25,22 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the jagged edge of a collapsed block
* takes up during rendering
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.blockRendering.JaggedEdge
* @struct
*/
const JaggedEdge = function(constants) {
JaggedEdge.superClass_.constructor.call(this, constants);
this.type |= Types.JAGGED_EDGE;
this.height = this.constants_.JAGGED_TEETH.height;
this.width = this.constants_.JAGGED_TEETH.width;
};
object.inherits(JaggedEdge, Measurable);
class JaggedEdge extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @alias Blockly.blockRendering.JaggedEdge
*/
constructor(constants) {
super(constants);
this.type |= Types.JAGGED_EDGE;
this.height = this.constants_.JAGGED_TEETH.height;
this.width = this.constants_.JAGGED_TEETH.width;
}
}
exports.JaggedEdge = JaggedEdge;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.NextConnection');
const object = goog.require('Blockly.utils.object');
const {Connection} = goog.require('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
@@ -28,21 +27,24 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a next connection takes
* up during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @constructor
* @extends {Connection}
* @alias Blockly.blockRendering.NextConnection
* @struct
*/
const NextConnection = function(constants, connectionModel) {
NextConnection.superClass_.constructor.call(this, constants, connectionModel);
this.type |= Types.NEXT_CONNECTION;
this.height = this.shape.height;
this.width = this.shape.width;
};
object.inherits(NextConnection, Connection);
class NextConnection extends Connection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @alias Blockly.blockRendering.NextConnection
*/
constructor(constants, connectionModel) {
super(constants, connectionModel);
this.type |= Types.NEXT_CONNECTION;
this.height = this.shape.height;
this.width = this.shape.width;
}
}
exports.NextConnection = NextConnection;

View File

@@ -17,7 +17,6 @@
*/
goog.module('Blockly.blockRendering.OutputConnection');
const object = goog.require('Blockly.utils.object');
const {Connection} = goog.require('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
@@ -29,27 +28,34 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space an output connection takes
* up during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @constructor
* @extends {Connection}
* @alias Blockly.blockRendering.OutputConnection
* @struct
*/
const OutputConnection = function(constants, connectionModel) {
OutputConnection.superClass_.constructor.call(
this, constants, connectionModel);
this.type |= Types.OUTPUT_CONNECTION;
class OutputConnection extends Connection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @alias Blockly.blockRendering.OutputConnection
*/
constructor(constants, connectionModel) {
super(constants, connectionModel);
this.type |= Types.OUTPUT_CONNECTION;
this.height = !this.isDynamicShape ? this.shape.height : 0;
this.width = !this.isDynamicShape ? this.shape.width : 0;
this.startX = this.width;
this.height = !this.isDynamicShape ? this.shape.height : 0;
this.width = !this.isDynamicShape ? this.shape.width : 0;
this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP;
this.connectionOffsetX = 0;
};
object.inherits(OutputConnection, Connection);
/** @type {number} */
this.startX = this.width;
/** @type {number} */
this.connectionOffsetY = this.constants_.TAB_OFFSET_FROM_TOP;
/** @type {number} */
this.connectionOffsetX = 0;
}
}
exports.OutputConnection = OutputConnection;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.PreviousConnection');
const object = goog.require('Blockly.utils.object');
const {Connection} = goog.require('Blockly.blockRendering.Connection');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
@@ -28,22 +27,24 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a previous connection takes
* up during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @constructor
* @extends {Connection}
* @alias Blockly.blockRendering.PreviousConnection
* @struct
*/
const PreviousConnection = function(constants, connectionModel) {
PreviousConnection.superClass_.constructor.call(
this, constants, connectionModel);
this.type |= Types.PREVIOUS_CONNECTION;
this.height = this.shape.height;
this.width = this.shape.width;
};
object.inherits(PreviousConnection, Connection);
class PreviousConnection extends Connection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!RenderedConnection} connectionModel The connection object on
* the block that this represents.
* @package
* @alias Blockly.blockRendering.PreviousConnection
*/
constructor(constants, connectionModel) {
super(constants, connectionModel);
this.type |= Types.PREVIOUS_CONNECTION;
this.height = this.shape.height;
this.width = this.shape.width;
}
}
exports.PreviousConnection = PreviousConnection;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.RoundCorner');
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,25 +25,28 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a rounded corner takes up
* during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {string=} opt_position The position of this corner.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.blockRendering.RoundCorner
* @struct
*/
const RoundCorner = function(constants, opt_position) {
RoundCorner.superClass_.constructor.call(this, constants);
this.type =
((!opt_position || opt_position === 'left') ? Types.LEFT_ROUND_CORNER :
Types.RIGHT_ROUND_CORNER) |
Types.CORNER;
this.width = this.constants_.CORNER_RADIUS;
// The rounded corner extends into the next row by 4 so we only take the
// height that is aligned with this row.
this.height = this.constants_.CORNER_RADIUS / 2;
};
object.inherits(RoundCorner, Measurable);
class RoundCorner extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {string=} opt_position The position of this corner.
* @package
* @alias Blockly.blockRendering.RoundCorner
*/
constructor(constants, opt_position) {
super(constants);
this.type = ((!opt_position || opt_position === 'left') ?
Types.LEFT_ROUND_CORNER :
Types.RIGHT_ROUND_CORNER) |
Types.CORNER;
this.width = this.constants_.CORNER_RADIUS;
// The rounded corner extends into the next row by 4 so we only take the
// height that is aligned with this row.
this.height = this.constants_.CORNER_RADIUS / 2;
}
}
exports.RoundCorner = RoundCorner;

View File

@@ -143,6 +143,9 @@ const Row = function(constants) {
*/
this.constants_ = constants;
/**
* @type {number}
*/
this.notchOffset = this.constants_.NOTCH_OFFSET_LEFT;
/**

View File

@@ -14,7 +14,6 @@
*/
goog.module('Blockly.blockRendering.SpacerRow');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InRowSpacer} = goog.require('Blockly.blockRendering.InRowSpacer');
@@ -24,31 +23,47 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about a spacer between two rows.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {number} height The height of the spacer.
* @param {number} width The width of the spacer.
* @package
* @constructor
* @extends {Row}
* @alias Blockly.blockRendering.SpacerRow
* @struct
*/
const SpacerRow = function(constants, height, width) {
SpacerRow.superClass_.constructor.call(this, constants);
this.type |= Types.SPACER | Types.BETWEEN_ROW_SPACER;
this.width = width;
this.height = height;
this.followsStatement = false;
this.widthWithConnectedBlocks = 0;
this.elements = [new InRowSpacer(this.constants_, width)];
};
object.inherits(SpacerRow, Row);
class SpacerRow extends Row {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {number} height The height of the spacer.
* @param {number} width The width of the spacer.
* @package
* @alias Blockly.blockRendering.SpacerRow
*/
constructor(constants, height, width) {
super(constants);
this.type |= Types.SPACER | Types.BETWEEN_ROW_SPACER;
/**
* @override
*/
SpacerRow.prototype.measure = function() {
// NOP. Width and height were set at creation.
};
/** @type {number} */
this.width = width;
/** @type {number} */
this.height = height;
/** @type {boolean} */
this.followsStatement = false;
/** @type {boolean} */
this.precedesStatement = false;
/** @type {number} */
this.widthWithConnectedBlocks = 0;
/** @type {!Array.<!InRowSpacer>} */
this.elements = [new InRowSpacer(this.constants_, width)];
}
/**
* @override
*/
measure() {
// NOP. Width and height were set at creation.
}
}
exports.SpacerRow = SpacerRow;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.SquareCorner');
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,23 +25,26 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* An object containing information about the space a square corner takes up
* during rendering.
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {string=} opt_position The position of this corner.
* @package
* @constructor
* @extends {Measurable}
* @alias Blockly.blockRendering.SquareCorner
* @struct
*/
const SquareCorner = function(constants, opt_position) {
SquareCorner.superClass_.constructor.call(this, constants);
this.type =
((!opt_position || opt_position === 'left') ? Types.LEFT_SQUARE_CORNER :
Types.RIGHT_SQUARE_CORNER) |
Types.CORNER;
this.height = this.constants_.NO_PADDING;
this.width = this.constants_.NO_PADDING;
};
object.inherits(SquareCorner, Measurable);
class SquareCorner extends Measurable {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {string=} opt_position The position of this corner.
* @package
* @alias Blockly.blockRendering.SquareCorner
*/
constructor(constants, opt_position) {
super(constants);
this.type = ((!opt_position || opt_position === 'left') ?
Types.LEFT_SQUARE_CORNER :
Types.RIGHT_SQUARE_CORNER) |
Types.CORNER;
this.height = this.constants_.NO_PADDING;
this.width = this.constants_.NO_PADDING;
}
}
exports.SquareCorner = SquareCorner;

View File

@@ -16,7 +16,6 @@
*/
goog.module('Blockly.blockRendering.StatementInput');
const object = goog.require('Blockly.utils.object');
/* eslint-disable-next-line no-unused-vars */
const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
const {InputConnection} = goog.require('Blockly.blockRendering.InputConnection');
@@ -28,29 +27,33 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
/**
* 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
* @struct
* @extends {InputConnection}
* @alias Blockly.blockRendering.StatementInput
*/
const StatementInput = function(constants, input) {
StatementInput.superClass_.constructor.call(this, constants, input);
this.type |= Types.STATEMENT_INPUT;
class StatementInput extends InputConnection {
/**
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @param {!Input} input The statement input to measure and store
* information for.
* @package
* @alias Blockly.blockRendering.StatementInput
*/
constructor(constants, input) {
super(constants, input);
this.type |= Types.STATEMENT_INPUT;
if (!this.connectedBlock) {
this.height = this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT;
} else {
// 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.connectedBlockHeight + this.constants_.STATEMENT_BOTTOM_SPACER;
if (!this.connectedBlock) {
this.height = this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT;
} else {
// 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.connectedBlockHeight + this.constants_.STATEMENT_BOTTOM_SPACER;
}
this.width =
this.constants_.STATEMENT_INPUT_NOTCH_OFFSET + this.shape.width;
}
this.width = this.constants_.STATEMENT_INPUT_NOTCH_OFFSET + this.shape.width;
};
object.inherits(StatementInput, InputConnection);
}
exports.StatementInput = StatementInput;

View File

@@ -14,7 +14,6 @@
*/
goog.module('Blockly.blockRendering.TopRow');
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 */
@@ -32,109 +31,112 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
* 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 {Row}
* @alias Blockly.blockRendering.TopRow
* @struct
*/
const TopRow = function(constants) {
TopRow.superClass_.constructor.call(this, constants);
this.type |= Types.TOP_ROW;
class TopRow extends Row {
/**
* The starting point for drawing the row, in the y direction.
* This allows us to draw hats and similar shapes that don't start at the
* origin. Must be non-negative (see #2820).
* @param {!ConstantProvider} constants The rendering
* constants provider.
* @package
* @type {number}
* @alias Blockly.blockRendering.TopRow
*/
this.capline = 0;
constructor(constants) {
super(constants);
this.type |= Types.TOP_ROW;
/**
* The starting point for drawing the row, in the y direction.
* This allows us to draw hats and similar shapes that don't start at the
* origin. Must be non-negative (see #2820).
* @package
* @type {number}
*/
this.capline = 0;
/**
* How much the row extends up above its capline.
* @type {number}
*/
this.ascenderHeight = 0;
/**
* Whether the block has a previous connection.
* @package
* @type {boolean}
*/
this.hasPreviousConnection = false;
/**
* The previous connection on the block, if any.
* @type {PreviousConnection}
*/
this.connection = null;
}
/**
* How much the row extends up above its capline.
* @type {number}
* Returns whether or not the top row has a left square corner.
* @param {!BlockSvg} block The block whose top row this represents.
* @return {boolean} Whether or not the top row has a left square corner.
*/
this.ascenderHeight = 0;
hasLeftSquareCorner(block) {
const hasHat =
(block.hat ? block.hat === 'cap' : this.constants_.ADD_START_HATS) &&
!block.outputConnection && !block.previousConnection;
const prevBlock = block.getPreviousBlock();
return !!block.outputConnection || hasHat ||
(prevBlock ? prevBlock.getNextBlock() === block : false);
}
/**
* Whether the block has a previous connection.
* @package
* @type {boolean}
* Returns whether or not the top row has a right square corner.
* @param {!BlockSvg} _block The block whose top row this represents.
* @return {boolean} Whether or not the top row has a right square corner.
*/
this.hasPreviousConnection = false;
hasRightSquareCorner(_block) {
return true;
}
/**
* The previous connection on the block, if any.
* @type {PreviousConnection}
* @override
*/
this.connection = null;
};
object.inherits(TopRow, Row);
/**
* Returns whether or not the top row has a left square corner.
* @param {!BlockSvg} block The block whose top row this represents.
* @return {boolean} Whether or not the top row has a left square corner.
*/
TopRow.prototype.hasLeftSquareCorner = function(block) {
const hasHat =
(block.hat ? block.hat === 'cap' : this.constants_.ADD_START_HATS) &&
!block.outputConnection && !block.previousConnection;
const prevBlock = block.getPreviousBlock();
return !!block.outputConnection || hasHat ||
(prevBlock ? prevBlock.getNextBlock() === block : false);
};
/**
* Returns whether or not the top row has a right square corner.
* @param {!BlockSvg} _block The block whose top row this represents.
* @return {boolean} Whether or not the top row has a right square corner.
*/
TopRow.prototype.hasRightSquareCorner = function(_block) {
return true;
};
/**
* @override
*/
TopRow.prototype.measure = function() {
let height = 0;
let width = 0;
let ascenderHeight = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
width += elem.width;
if (!(Types.isSpacer(elem))) {
if (Types.isHat(elem)) {
ascenderHeight = Math.max(ascenderHeight, elem.ascenderHeight);
} else {
height = Math.max(height, elem.height);
measure() {
let height = 0;
let width = 0;
let ascenderHeight = 0;
for (let i = 0; i < this.elements.length; i++) {
const elem = this.elements[i];
width += elem.width;
if (!(Types.isSpacer(elem))) {
if (Types.isHat(elem)) {
ascenderHeight = Math.max(ascenderHeight, elem.ascenderHeight);
} else {
height = Math.max(height, elem.height);
}
}
}
this.width = Math.max(this.minWidth, width);
this.height = Math.max(this.minHeight, height) + ascenderHeight;
this.ascenderHeight = ascenderHeight;
this.capline = this.ascenderHeight;
this.widthWithConnectedBlocks = this.width;
}
this.width = Math.max(this.minWidth, width);
this.height = Math.max(this.minHeight, height) + ascenderHeight;
this.ascenderHeight = ascenderHeight;
this.capline = this.ascenderHeight;
this.widthWithConnectedBlocks = this.width;
};
/**
* @override
*/
TopRow.prototype.startsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
startsWithElemSpacer() {
return false;
}
/**
* @override
*/
TopRow.prototype.endsWithElemSpacer = function() {
return false;
};
/**
* @override
*/
endsWithElemSpacer() {
return false;
}
}
exports.TopRow = TopRow;

View File

@@ -20,11 +20,15 @@ goog.module('Blockly.thrasos.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
const {BottomRow} = goog.requireType('Blockly.blockRendering.BottomRow');
/* eslint-disable-next-line no-unused-vars */
const {Field} = goog.requireType('Blockly.blockRendering.Field');
const {InRowSpacer} = goog.require('Blockly.blockRendering.InRowSpacer');
const {RenderInfo: BaseRenderInfo} = goog.require('Blockly.blockRendering.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {Renderer} = goog.requireType('Blockly.thrasos.Renderer');
/* eslint-disable-next-line no-unused-vars */
const {TopRow} = goog.requireType('Blockly.blockRendering.TopRow');
const {Types} = goog.require('Blockly.blockRendering.Types');
@@ -261,17 +265,20 @@ class RenderInfo extends BaseRenderInfo {
return row.yPos + elem.height / 2;
}
if (Types.isBottomRow(row)) {
const baseline = row.yPos + row.height - row.descenderHeight;
const bottomRow = /** @type {!BottomRow} */ (row);
const baseline =
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
if (Types.isNextConnection(elem)) {
return baseline + elem.height / 2;
}
return baseline - elem.height / 2;
}
if (Types.isTopRow(row)) {
const topRow = /** @type {!TopRow} */ (row);
if (Types.isHat(elem)) {
return row.capline - elem.height / 2;
return topRow.capline - elem.height / 2;
}
return row.capline + elem.height / 2;
return topRow.capline + elem.height / 2;
}
let result = row.yPos;

View File

@@ -26,6 +26,11 @@ const {PathObject} = goog.requireType('Blockly.zelos.PathObject');
const {RenderInfo} = goog.requireType('Blockly.zelos.RenderInfo');
/* eslint-disable-next-line no-unused-vars */
const {Row} = goog.requireType('Blockly.blockRendering.Row');
/* eslint-disable-next-line no-unused-vars */
const {SpacerRow} = goog.requireType('Blockly.blockRendering.SpacerRow');
/* eslint-disable-next-line no-unused-vars */
const {StatementInput} = goog.requireType('Blockly.zelos.StatementInput');
const {Types} = goog.require('Blockly.blockRendering.Types');
/**
@@ -111,21 +116,26 @@ class Drawer extends BaseDrawer {
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);
if (Types.isSpacer(row)) {
const spacerRow = /** @type {!SpacerRow} */ (row);
if (spacerRow.precedesStatement || spacerRow.followsStatement) {
const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight;
const remainingHeight =
spacerRow.height - (spacerRow.precedesStatement ? cornerHeight : 0);
this.outlinePath_ +=
(spacerRow.followsStatement ?
this.constants_.INSIDE_CORNERS.pathBottomRight :
'') +
(remainingHeight > 0 ?
svgPaths.lineOnAxis('V', spacerRow.yPos + remainingHeight) :
'') +
(spacerRow.precedesStatement ?
this.constants_.INSIDE_CORNERS.pathTopRight :
'');
return;
}
}
this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
}
/**
@@ -207,7 +217,7 @@ class Drawer extends BaseDrawer {
* @override
*/
drawStatementInput_(row) {
const input = row.getLastInput();
const input = /** @type {!StatementInput} */ (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;

View File

@@ -32,6 +32,8 @@ const {RenderInfo: BaseRenderInfo} = goog.require('Blockly.blockRendering.Render
/* eslint-disable-next-line no-unused-vars */
const {Renderer} = goog.requireType('Blockly.zelos.Renderer');
const {RightConnectionShape} = goog.require('Blockly.zelos.RightConnectionShape');
/* eslint-disable-next-line no-unused-vars */
const {SpacerRow} = goog.requireType('Blockly.blockRendering.SpacerRow');
const {StatementInput} = goog.require('Blockly.zelos.StatementInput');
const {TopRow} = goog.require('Blockly.zelos.TopRow');
const {Types} = goog.require('Blockly.blockRendering.Types');
@@ -202,7 +204,8 @@ class RenderInfo extends BaseRenderInfo {
}
// Top and bottom rows act as a spacer so we don't need any extra padding.
if (Types.isTopRow(prev)) {
if (!prev.hasPreviousConnection &&
const topRow = /** @type {!TopRow} */ (prev);
if (!topRow.hasPreviousConnection &&
(!this.outputConnection || this.hasStatementInput)) {
return Math.abs(
this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
@@ -210,6 +213,7 @@ class RenderInfo extends BaseRenderInfo {
return this.constants_.NO_PADDING;
}
if (Types.isBottomRow(next)) {
const bottomRow = /** @type {!BottomRow} */ (next);
if (!this.outputConnection) {
const topHeight = Math.max(
this.topRow.minHeight,
@@ -218,7 +222,7 @@ class RenderInfo extends BaseRenderInfo {
this.constants_.CORNER_RADIUS)) -
this.constants_.CORNER_RADIUS;
return topHeight;
} else if (!next.hasNextConnection && this.hasStatementInput) {
} else if (!bottomRow.hasNextConnection && this.hasStatementInput) {
return Math.abs(
this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
}
@@ -319,9 +323,9 @@ class RenderInfo extends BaseRenderInfo {
// first input row (if the block has prev connection) and every input row
// that has a prev and next notch.
for (let i = 2; i < this.rows.length - 1; i += 2) {
const prevSpacer = this.rows[i - 1];
const prevSpacer = /** @type {!SpacerRow} */ (this.rows[i - 1]);
const row = this.rows[i];
const nextSpacer = this.rows[i + 1];
const nextSpacer = /** @type {!SpacerRow} */ (this.rows[i + 1]);
const hasPrevNotch = i === 2 ? !!this.topRow.hasPreviousConnection :
!!prevSpacer.followsStatement;
@@ -536,9 +540,9 @@ class RenderInfo extends BaseRenderInfo {
// Run through every input row on the block and only apply tight nesting
// logic to input rows that have a prev and next notch.
for (let i = 2; i < this.rows.length - 1; i += 2) {
const prevSpacer = this.rows[i - 1];
const prevSpacer = /** @type {!SpacerRow} */ (this.rows[i - 1]);
const row = this.rows[i];
const nextSpacer = this.rows[i + 1];
const nextSpacer = /** @type {!SpacerRow} */ (this.rows[i + 1]);
const firstRow = i === 2;
const hasPrevNotch = firstRow ? !!this.topRow.hasPreviousConnection :