mirror of
https://github.com/google/blockly.git
synced 2026-03-09 14:50:09 +01:00
refactor: Convert renderer typecheck methods to typeguards. (#8656)
* refactor: Convert renderer typecheck methods to typeguards. * chore: Revert unintended change. * chore: Format types.ts.
This commit is contained in:
@@ -15,7 +15,6 @@ import type {ExternalValueInput} from '../measurables/external_value_input.js';
|
||||
import type {Field} from '../measurables/field.js';
|
||||
import type {Icon} from '../measurables/icon.js';
|
||||
import type {InlineInput} from '../measurables/inline_input.js';
|
||||
import type {PreviousConnection} from '../measurables/previous_connection.js';
|
||||
import type {Row} from '../measurables/row.js';
|
||||
import {Types} from '../measurables/types.js';
|
||||
import type {ConstantProvider, Notch, PuzzleTab} from './constants.js';
|
||||
@@ -116,13 +115,8 @@ export class Drawer {
|
||||
this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft;
|
||||
} else if (Types.isRightRoundedCorner(elem)) {
|
||||
this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight;
|
||||
} else if (
|
||||
Types.isPreviousConnection(elem) &&
|
||||
elem instanceof Connection
|
||||
) {
|
||||
this.outlinePath_ += (
|
||||
(elem as PreviousConnection).shape as Notch
|
||||
).pathLeft;
|
||||
} else if (Types.isPreviousConnection(elem)) {
|
||||
this.outlinePath_ += (elem.shape as Notch).pathLeft;
|
||||
} else if (Types.isHat(elem)) {
|
||||
this.outlinePath_ += this.constants_.START_HAT.path;
|
||||
} else if (Types.isSpacer(elem)) {
|
||||
@@ -217,7 +211,7 @@ export class Drawer {
|
||||
let rightCornerYOffset = 0;
|
||||
let outlinePath = '';
|
||||
for (let i = elems.length - 1, elem; (elem = elems[i]); i--) {
|
||||
if (Types.isNextConnection(elem) && elem instanceof Connection) {
|
||||
if (Types.isNextConnection(elem)) {
|
||||
outlinePath += (elem.shape as Notch).pathRight;
|
||||
} else if (Types.isLeftSquareCorner(elem)) {
|
||||
outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos);
|
||||
@@ -269,9 +263,9 @@ export class Drawer {
|
||||
for (let i = 0, row; (row = this.info_.rows[i]); i++) {
|
||||
for (let j = 0, elem; (elem = row.elements[j]); j++) {
|
||||
if (Types.isInlineInput(elem)) {
|
||||
this.drawInlineInput_(elem as InlineInput);
|
||||
this.drawInlineInput_(elem);
|
||||
} else if (Types.isIcon(elem) || Types.isField(elem)) {
|
||||
this.layoutField_(elem as Field | Icon);
|
||||
this.layoutField_(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,13 +289,13 @@ export class Drawer {
|
||||
}
|
||||
|
||||
if (Types.isIcon(fieldInfo)) {
|
||||
const icon = (fieldInfo as Icon).icon;
|
||||
const icon = fieldInfo.icon;
|
||||
icon.setOffsetInBlock(new Coordinate(xPos, yPos));
|
||||
if (this.info_.isInsertionMarker) {
|
||||
icon.hideForInsertionMarker();
|
||||
}
|
||||
} else {
|
||||
const svgGroup = (fieldInfo as Field).field.getSvgRoot()!;
|
||||
const svgGroup = fieldInfo.field.getSvgRoot()!;
|
||||
svgGroup.setAttribute(
|
||||
'transform',
|
||||
'translate(' + xPos + ',' + yPos + ')' + scale,
|
||||
|
||||
@@ -671,20 +671,17 @@ export class RenderInfo {
|
||||
return row.yPos + elem.height / 2;
|
||||
}
|
||||
if (Types.isBottomRow(row)) {
|
||||
const bottomRow = row as BottomRow;
|
||||
const baseline =
|
||||
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
|
||||
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)) {
|
||||
const topRow = row as TopRow;
|
||||
if (Types.isHat(elem)) {
|
||||
return topRow.capline - elem.height / 2;
|
||||
return row.capline - elem.height / 2;
|
||||
}
|
||||
return topRow.capline + elem.height / 2;
|
||||
return row.capline + elem.height / 2;
|
||||
}
|
||||
return row.yPos + row.height / 2;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export class Drawer extends BaseDrawer {
|
||||
}
|
||||
|
||||
override drawInlineInput_(input: InlineInput) {
|
||||
this.highlighter_.drawInlineInput(input as InlineInput);
|
||||
this.highlighter_.drawInlineInput(input);
|
||||
|
||||
super.drawInlineInput_(input);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,9 @@ import {StatementInput} from '../../inputs/statement_input.js';
|
||||
import {ValueInput} from '../../inputs/value_input.js';
|
||||
import {RenderInfo as BaseRenderInfo} from '../common/info.js';
|
||||
import type {Measurable} from '../measurables/base.js';
|
||||
import type {BottomRow} from '../measurables/bottom_row.js';
|
||||
import {ExternalValueInput} from '../measurables/external_value_input.js';
|
||||
import type {Field} from '../measurables/field.js';
|
||||
import {InRowSpacer} from '../measurables/in_row_spacer.js';
|
||||
import type {InputRow} from '../measurables/input_row.js';
|
||||
import type {Row} from '../measurables/row.js';
|
||||
import type {TopRow} from '../measurables/top_row.js';
|
||||
import {Types} from '../measurables/types.js';
|
||||
import type {ConstantProvider} from './constants.js';
|
||||
import {InlineInput} from './measurables/inline_input.js';
|
||||
@@ -150,7 +146,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
override getInRowSpacing_(prev: Measurable | null, next: Measurable | null) {
|
||||
if (!prev) {
|
||||
// Between an editable field and the beginning of the row.
|
||||
if (next && Types.isField(next) && (next as Field).isEditable) {
|
||||
if (next && Types.isField(next) && next.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
}
|
||||
// Inline input at the beginning of the row.
|
||||
@@ -167,7 +163,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// 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) && (prev as Field).isEditable) {
|
||||
if (Types.isField(prev) && prev.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
}
|
||||
// Padding at the end of an icon-only row to make the block shape clearer.
|
||||
@@ -208,7 +204,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// 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) && (prev as Field).isEditable) {
|
||||
if (Types.isField(prev) && prev.isEditable) {
|
||||
if (Types.isInlineInput(next)) {
|
||||
return this.constants_.SMALL_PADDING;
|
||||
} else if (Types.isExternalInput(next)) {
|
||||
@@ -233,7 +229,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// Spacing between an inline input and a field.
|
||||
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
|
||||
// Editable field after inline input.
|
||||
if ((next as Field).isEditable) {
|
||||
if (next.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
} else {
|
||||
// Noneditable field after inline input.
|
||||
@@ -278,7 +274,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
Types.isField(prev) &&
|
||||
next &&
|
||||
Types.isField(next) &&
|
||||
(prev as Field).isEditable === (next as Field).isEditable
|
||||
prev.isEditable === next.isEditable
|
||||
) {
|
||||
return this.constants_.LARGE_PADDING;
|
||||
}
|
||||
@@ -323,20 +319,17 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
return row.yPos + elem.height / 2;
|
||||
}
|
||||
if (Types.isBottomRow(row)) {
|
||||
const bottomRow = row as BottomRow;
|
||||
const baseline =
|
||||
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
|
||||
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)) {
|
||||
const topRow = row as TopRow;
|
||||
if (Types.isHat(elem)) {
|
||||
return topRow.capline - elem.height / 2;
|
||||
return row.capline - elem.height / 2;
|
||||
}
|
||||
return topRow.capline + elem.height / 2;
|
||||
return row.capline + elem.height / 2;
|
||||
}
|
||||
|
||||
let result = row.yPos;
|
||||
@@ -370,7 +363,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
rowNextRightEdges.set(row, nextRightEdge);
|
||||
if (Types.isInputRow(row)) {
|
||||
if (row.hasStatement) {
|
||||
this.alignStatementRow_(row as InputRow);
|
||||
this.alignStatementRow_(row);
|
||||
}
|
||||
if (
|
||||
prevInput &&
|
||||
|
||||
@@ -15,6 +15,14 @@ import {Types} from './types.js';
|
||||
* row.
|
||||
*/
|
||||
export class InRowSpacer extends Measurable {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private inRowSpacer: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param width The width of the spacer.
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
// Former goog.module ID: Blockly.blockRendering.InputRow
|
||||
|
||||
import type {ConstantProvider} from '../common/constants.js';
|
||||
import {ExternalValueInput} from './external_value_input.js';
|
||||
import {InputConnection} from './input_connection.js';
|
||||
import {Row} from './row.js';
|
||||
import {StatementInput} from './statement_input.js';
|
||||
import {Types} from './types.js';
|
||||
|
||||
/**
|
||||
@@ -40,12 +37,11 @@ export class InputRow extends Row {
|
||||
for (let i = 0; i < this.elements.length; i++) {
|
||||
const elem = this.elements[i];
|
||||
this.width += elem.width;
|
||||
if (Types.isInput(elem) && elem instanceof InputConnection) {
|
||||
if (Types.isStatementInput(elem) && elem instanceof StatementInput) {
|
||||
if (Types.isInput(elem)) {
|
||||
if (Types.isStatementInput(elem)) {
|
||||
connectedBlockWidths += elem.connectedBlockWidth;
|
||||
} else if (
|
||||
Types.isExternalInput(elem) &&
|
||||
elem instanceof ExternalValueInput &&
|
||||
elem.connectedBlockWidth !== 0
|
||||
) {
|
||||
connectedBlockWidths +=
|
||||
|
||||
@@ -15,6 +15,14 @@ import {Types} from './types.js';
|
||||
* collapsed block takes up during rendering.
|
||||
*/
|
||||
export class JaggedEdge extends Measurable {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private jaggedEdge: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,14 @@ import {Types} from './types.js';
|
||||
* up during rendering.
|
||||
*/
|
||||
export class NextConnection extends Connection {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private nextConnection: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param connectionModel The connection object on the block that this
|
||||
|
||||
@@ -16,6 +16,14 @@ import {Types} from './types.js';
|
||||
* up during rendering.
|
||||
*/
|
||||
export class PreviousConnection extends Connection {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private previousConnection: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param connectionModel The connection object on the block that this
|
||||
|
||||
@@ -15,6 +15,14 @@ import {Types} from './types.js';
|
||||
* during rendering.
|
||||
*/
|
||||
export class RoundCorner extends Measurable {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private roundCorner: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param opt_position The position of this corner.
|
||||
|
||||
@@ -127,7 +127,7 @@ export class Row {
|
||||
for (let i = this.elements.length - 1; i >= 0; i--) {
|
||||
const elem = this.elements[i];
|
||||
if (Types.isInput(elem)) {
|
||||
return elem as InputConnection;
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -166,8 +166,8 @@ export class Row {
|
||||
getFirstSpacer(): InRowSpacer | null {
|
||||
for (let i = 0; i < this.elements.length; i++) {
|
||||
const elem = this.elements[i];
|
||||
if (Types.isSpacer(elem)) {
|
||||
return elem as InRowSpacer;
|
||||
if (Types.isInRowSpacer(elem)) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -181,8 +181,8 @@ export class Row {
|
||||
getLastSpacer(): InRowSpacer | null {
|
||||
for (let i = this.elements.length - 1; i >= 0; i--) {
|
||||
const elem = this.elements[i];
|
||||
if (Types.isSpacer(elem)) {
|
||||
return elem as InRowSpacer;
|
||||
if (Types.isInRowSpacer(elem)) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -15,6 +15,14 @@ import {Types} from './types.js';
|
||||
* during rendering.
|
||||
*/
|
||||
export class SquareCorner extends Measurable {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private squareCorner: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param opt_position The position of this corner.
|
||||
|
||||
@@ -16,6 +16,14 @@ import {Types} from './types.js';
|
||||
* during rendering
|
||||
*/
|
||||
export class StatementInput extends InputConnection {
|
||||
// This field exists solely to structurally distinguish this type from other
|
||||
// Measurable subclasses. Because this class otherwise has the same fields as
|
||||
// Measurable, and Typescript doesn't support nominal typing, Typescript will
|
||||
// consider it and other subclasses in the same situation as being of the same
|
||||
// type, even if typeguards are used, which could result in Typescript typing
|
||||
// objects of this class as `never`.
|
||||
private statementInput: undefined;
|
||||
|
||||
/**
|
||||
* @param constants The rendering constants provider.
|
||||
* @param input The statement input to measure and store information for.
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import type {BlockSvg} from '../../block_svg.js';
|
||||
import type {ConstantProvider} from '../common/constants.js';
|
||||
import {Hat} from './hat.js';
|
||||
import type {PreviousConnection} from './previous_connection.js';
|
||||
import {Row} from './row.js';
|
||||
import {Types} from './types.js';
|
||||
@@ -85,7 +84,7 @@ export class TopRow extends Row {
|
||||
const elem = this.elements[i];
|
||||
width += elem.width;
|
||||
if (!Types.isSpacer(elem)) {
|
||||
if (Types.isHat(elem) && elem instanceof Hat) {
|
||||
if (Types.isHat(elem)) {
|
||||
ascenderHeight = Math.max(ascenderHeight, elem.ascenderHeight);
|
||||
} else {
|
||||
height = Math.max(height, elem.height);
|
||||
|
||||
@@ -7,7 +7,24 @@
|
||||
// Former goog.module ID: Blockly.blockRendering.Types
|
||||
|
||||
import type {Measurable} from './base.js';
|
||||
import type {BottomRow} from './bottom_row.js';
|
||||
import type {ExternalValueInput} from './external_value_input.js';
|
||||
import type {Field} from './field.js';
|
||||
import type {Hat} from './hat.js';
|
||||
import type {Icon} from './icon.js';
|
||||
import type {InRowSpacer} from './in_row_spacer.js';
|
||||
import type {InlineInput} from './inline_input.js';
|
||||
import type {InputConnection} from './input_connection.js';
|
||||
import type {InputRow} from './input_row.js';
|
||||
import type {JaggedEdge} from './jagged_edge.js';
|
||||
import type {NextConnection} from './next_connection.js';
|
||||
import type {PreviousConnection} from './previous_connection.js';
|
||||
import type {RoundCorner} from './round_corner.js';
|
||||
import type {Row} from './row.js';
|
||||
import type {SpacerRow} from './spacer_row.js';
|
||||
import type {SquareCorner} from './square_corner.js';
|
||||
import type {StatementInput} from './statement_input.js';
|
||||
import type {TopRow} from './top_row.js';
|
||||
|
||||
/**
|
||||
* Types of rendering elements.
|
||||
@@ -82,8 +99,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a field.
|
||||
*/
|
||||
isField(elem: Measurable): number {
|
||||
return elem.type & this.FIELD;
|
||||
isField(elem: Measurable): elem is Field {
|
||||
return (elem.type & this.FIELD) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,8 +109,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a hat.
|
||||
*/
|
||||
isHat(elem: Measurable): number {
|
||||
return elem.type & this.HAT;
|
||||
isHat(elem: Measurable): elem is Hat {
|
||||
return (elem.type & this.HAT) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,8 +119,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about an icon.
|
||||
*/
|
||||
isIcon(elem: Measurable): number {
|
||||
return elem.type & this.ICON;
|
||||
isIcon(elem: Measurable): elem is Icon {
|
||||
return (elem.type & this.ICON) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,8 +129,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a spacer.
|
||||
*/
|
||||
isSpacer(elem: Measurable | Row): number {
|
||||
return elem.type & this.SPACER;
|
||||
isSpacer(elem: Measurable | Row): elem is SpacerRow | InRowSpacer {
|
||||
return (elem.type & this.SPACER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +139,18 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about an in-row spacer.
|
||||
*/
|
||||
isInRowSpacer(elem: Measurable): number {
|
||||
return elem.type & this.IN_ROW_SPACER;
|
||||
isInRowSpacer(elem: Measurable): elem is InRowSpacer {
|
||||
return (elem.type & this.IN_ROW_SPACER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a row is a spacer row.
|
||||
*
|
||||
* @param row The row to check.
|
||||
* @returns True if the row is a spacer row.
|
||||
*/
|
||||
isSpacerRow(row: Row): row is SpacerRow {
|
||||
return (row.type & this.BETWEEN_ROW_SPACER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,8 +159,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about an input.
|
||||
*/
|
||||
isInput(elem: Measurable): number {
|
||||
return elem.type & this.INPUT;
|
||||
isInput(elem: Measurable): elem is InputConnection {
|
||||
return (elem.type & this.INPUT) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,8 +169,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about an external input.
|
||||
*/
|
||||
isExternalInput(elem: Measurable): number {
|
||||
return elem.type & this.EXTERNAL_VALUE_INPUT;
|
||||
isExternalInput(elem: Measurable): elem is ExternalValueInput {
|
||||
return (elem.type & this.EXTERNAL_VALUE_INPUT) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,8 +179,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about an inline input.
|
||||
*/
|
||||
isInlineInput(elem: Measurable): number {
|
||||
return elem.type & this.INLINE_INPUT;
|
||||
isInlineInput(elem: Measurable): elem is InlineInput {
|
||||
return (elem.type & this.INLINE_INPUT) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,8 +189,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a statement input.
|
||||
*/
|
||||
isStatementInput(elem: Measurable): number {
|
||||
return elem.type & this.STATEMENT_INPUT;
|
||||
isStatementInput(elem: Measurable): elem is StatementInput {
|
||||
return (elem.type & this.STATEMENT_INPUT) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,8 +199,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a previous connection.
|
||||
*/
|
||||
isPreviousConnection(elem: Measurable): number {
|
||||
return elem.type & this.PREVIOUS_CONNECTION;
|
||||
isPreviousConnection(elem: Measurable): elem is PreviousConnection {
|
||||
return (elem.type & this.PREVIOUS_CONNECTION) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,8 +209,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a next connection.
|
||||
*/
|
||||
isNextConnection(elem: Measurable): number {
|
||||
return elem.type & this.NEXT_CONNECTION;
|
||||
isNextConnection(elem: Measurable): elem is NextConnection {
|
||||
return (elem.type & this.NEXT_CONNECTION) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,8 +221,17 @@ class TypesContainer {
|
||||
* @returns 1 if the object stores information about a previous or next
|
||||
* connection.
|
||||
*/
|
||||
isPreviousOrNextConnection(elem: Measurable): number {
|
||||
return elem.type & (this.PREVIOUS_CONNECTION | this.NEXT_CONNECTION);
|
||||
isPreviousOrNextConnection(
|
||||
elem: Measurable,
|
||||
): elem is PreviousConnection | NextConnection {
|
||||
return this.isPreviousConnection(elem) || this.isNextConnection(elem);
|
||||
}
|
||||
|
||||
isRoundCorner(elem: Measurable): elem is RoundCorner {
|
||||
return (
|
||||
(elem.type & this.LEFT_ROUND_CORNER) >= 1 ||
|
||||
(elem.type & this.RIGHT_ROUND_CORNER) >= 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,8 +240,10 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a left round corner.
|
||||
*/
|
||||
isLeftRoundedCorner(elem: Measurable): number {
|
||||
return elem.type & this.LEFT_ROUND_CORNER;
|
||||
isLeftRoundedCorner(elem: Measurable): boolean {
|
||||
return (
|
||||
this.isRoundCorner(elem) && (elem.type & this.LEFT_ROUND_CORNER) >= 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,8 +252,10 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a right round corner.
|
||||
*/
|
||||
isRightRoundedCorner(elem: Measurable): number {
|
||||
return elem.type & this.RIGHT_ROUND_CORNER;
|
||||
isRightRoundedCorner(elem: Measurable): boolean {
|
||||
return (
|
||||
this.isRoundCorner(elem) && (elem.type & this.RIGHT_ROUND_CORNER) >= 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,8 +264,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a left square corner.
|
||||
*/
|
||||
isLeftSquareCorner(elem: Measurable): number {
|
||||
return elem.type & this.LEFT_SQUARE_CORNER;
|
||||
isLeftSquareCorner(elem: Measurable): boolean {
|
||||
return (elem.type & this.LEFT_SQUARE_CORNER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,8 +274,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a right square corner.
|
||||
*/
|
||||
isRightSquareCorner(elem: Measurable): number {
|
||||
return elem.type & this.RIGHT_SQUARE_CORNER;
|
||||
isRightSquareCorner(elem: Measurable): boolean {
|
||||
return (elem.type & this.RIGHT_SQUARE_CORNER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,8 +284,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a corner.
|
||||
*/
|
||||
isCorner(elem: Measurable): number {
|
||||
return elem.type & this.CORNER;
|
||||
isCorner(elem: Measurable): elem is SquareCorner | RoundCorner {
|
||||
return (elem.type & this.CORNER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,8 +294,8 @@ class TypesContainer {
|
||||
* @param elem The element to check.
|
||||
* @returns 1 if the object stores information about a jagged edge.
|
||||
*/
|
||||
isJaggedEdge(elem: Measurable): number {
|
||||
return elem.type & this.JAGGED_EDGE;
|
||||
isJaggedEdge(elem: Measurable): elem is JaggedEdge {
|
||||
return (elem.type & this.JAGGED_EDGE) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,8 +304,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about a row.
|
||||
*/
|
||||
isRow(row: Row): number {
|
||||
return row.type & this.ROW;
|
||||
isRow(row: Row): row is Row {
|
||||
return (row.type & this.ROW) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,8 +314,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about a between-row spacer.
|
||||
*/
|
||||
isBetweenRowSpacer(row: Row): number {
|
||||
return row.type & this.BETWEEN_ROW_SPACER;
|
||||
isBetweenRowSpacer(row: Row): row is SpacerRow {
|
||||
return (row.type & this.BETWEEN_ROW_SPACER) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,8 +324,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about a top row.
|
||||
*/
|
||||
isTopRow(row: Row): number {
|
||||
return row.type & this.TOP_ROW;
|
||||
isTopRow(row: Row): row is TopRow {
|
||||
return (row.type & this.TOP_ROW) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,8 +334,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about a bottom row.
|
||||
*/
|
||||
isBottomRow(row: Row): number {
|
||||
return row.type & this.BOTTOM_ROW;
|
||||
isBottomRow(row: Row): row is BottomRow {
|
||||
return (row.type & this.BOTTOM_ROW) >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,8 +344,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about a top or bottom row.
|
||||
*/
|
||||
isTopOrBottomRow(row: Row): number {
|
||||
return row.type & (this.TOP_ROW | this.BOTTOM_ROW);
|
||||
isTopOrBottomRow(row: Row): row is TopRow | BottomRow {
|
||||
return this.isTopRow(row) || this.isBottomRow(row);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,8 +354,8 @@ class TypesContainer {
|
||||
* @param row The row to check.
|
||||
* @returns 1 if the object stores information about an input row.
|
||||
*/
|
||||
isInputRow(row: Row): number {
|
||||
return row.type & this.INPUT_ROW;
|
||||
isInputRow(row: Row): row is InputRow {
|
||||
return (row.type & this.INPUT_ROW) >= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,8 @@
|
||||
import type {BlockSvg} from '../../block_svg.js';
|
||||
import {RenderInfo as BaseRenderInfo} from '../common/info.js';
|
||||
import type {Measurable} from '../measurables/base.js';
|
||||
import type {BottomRow} from '../measurables/bottom_row.js';
|
||||
import type {Field} from '../measurables/field.js';
|
||||
import {InRowSpacer} from '../measurables/in_row_spacer.js';
|
||||
import type {Row} from '../measurables/row.js';
|
||||
import type {TopRow} from '../measurables/top_row.js';
|
||||
import {Types} from '../measurables/types.js';
|
||||
import type {Renderer} from './renderer.js';
|
||||
|
||||
@@ -94,7 +91,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
override getInRowSpacing_(prev: Measurable | null, next: Measurable | null) {
|
||||
if (!prev) {
|
||||
// Between an editable field and the beginning of the row.
|
||||
if (next && Types.isField(next) && (next as Field).isEditable) {
|
||||
if (next && Types.isField(next) && next.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
}
|
||||
// Inline input at the beginning of the row.
|
||||
@@ -111,7 +108,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// 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) && (prev as Field).isEditable) {
|
||||
if (Types.isField(prev) && prev.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
}
|
||||
// Padding at the end of an icon-only row to make the block shape clearer.
|
||||
@@ -151,7 +148,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// 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) && (prev as Field).isEditable) {
|
||||
if (Types.isField(prev) && prev.isEditable) {
|
||||
if (Types.isInlineInput(next)) {
|
||||
return this.constants_.SMALL_PADDING;
|
||||
} else if (Types.isExternalInput(next)) {
|
||||
@@ -177,7 +174,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
// Spacing between an inline input and a field.
|
||||
if (Types.isInlineInput(prev) && next && Types.isField(next)) {
|
||||
// Editable field after inline input.
|
||||
if ((next as Field).isEditable) {
|
||||
if (next.isEditable) {
|
||||
return this.constants_.MEDIUM_PADDING;
|
||||
} else {
|
||||
// Noneditable field after inline input.
|
||||
@@ -205,7 +202,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
Types.isField(prev) &&
|
||||
next &&
|
||||
Types.isField(next) &&
|
||||
(prev as Field).isEditable === (next as Field).isEditable
|
||||
prev.isEditable === next.isEditable
|
||||
) {
|
||||
return this.constants_.LARGE_PADDING;
|
||||
}
|
||||
@@ -247,20 +244,17 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
return row.yPos + elem.height / 2;
|
||||
}
|
||||
if (Types.isBottomRow(row)) {
|
||||
const bottomRow = row as BottomRow;
|
||||
const baseline =
|
||||
bottomRow.yPos + bottomRow.height - bottomRow.descenderHeight;
|
||||
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)) {
|
||||
const topRow = row as TopRow;
|
||||
if (Types.isHat(elem)) {
|
||||
return topRow.capline - elem.height / 2;
|
||||
return row.capline - elem.height / 2;
|
||||
}
|
||||
return topRow.capline + elem.height / 2;
|
||||
return row.capline + elem.height / 2;
|
||||
}
|
||||
|
||||
let result = row.yPos;
|
||||
|
||||
@@ -15,7 +15,6 @@ import {Connection} from '../measurables/connection.js';
|
||||
import type {InlineInput} from '../measurables/inline_input.js';
|
||||
import {OutputConnection} from '../measurables/output_connection.js';
|
||||
import type {Row} from '../measurables/row.js';
|
||||
import type {SpacerRow} from '../measurables/spacer_row.js';
|
||||
import {Types} from '../measurables/types.js';
|
||||
import type {InsideCorners} from './constants.js';
|
||||
import type {RenderInfo} from './info.js';
|
||||
@@ -96,20 +95,19 @@ export class Drawer extends BaseDrawer {
|
||||
return;
|
||||
}
|
||||
if (Types.isSpacer(row)) {
|
||||
const spacerRow = row as SpacerRow;
|
||||
const precedesStatement = spacerRow.precedesStatement;
|
||||
const followsStatement = spacerRow.followsStatement;
|
||||
const precedesStatement = row.precedesStatement;
|
||||
const followsStatement = row.followsStatement;
|
||||
if (precedesStatement || followsStatement) {
|
||||
const insideCorners = this.constants_.INSIDE_CORNERS as InsideCorners;
|
||||
const cornerHeight = insideCorners.rightHeight;
|
||||
const remainingHeight =
|
||||
spacerRow.height - (precedesStatement ? cornerHeight : 0);
|
||||
row.height - (precedesStatement ? cornerHeight : 0);
|
||||
const bottomRightPath = followsStatement
|
||||
? insideCorners.pathBottomRight
|
||||
: '';
|
||||
const verticalPath =
|
||||
remainingHeight > 0
|
||||
? svgPaths.lineOnAxis('V', spacerRow.yPos + remainingHeight)
|
||||
? svgPaths.lineOnAxis('V', row.yPos + remainingHeight)
|
||||
: '';
|
||||
const topRightPath = precedesStatement
|
||||
? insideCorners.pathTopRight
|
||||
|
||||
@@ -20,7 +20,6 @@ import {RenderInfo as BaseRenderInfo} from '../common/info.js';
|
||||
import type {Measurable} from '../measurables/base.js';
|
||||
import {Field} from '../measurables/field.js';
|
||||
import {InRowSpacer} from '../measurables/in_row_spacer.js';
|
||||
import {InputConnection} from '../measurables/input_connection.js';
|
||||
import type {Row} from '../measurables/row.js';
|
||||
import type {SpacerRow} from '../measurables/spacer_row.js';
|
||||
import {Types} from '../measurables/types.js';
|
||||
@@ -207,9 +206,8 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
}
|
||||
// Top and bottom rows act as a spacer so we don't need any extra padding.
|
||||
if (Types.isTopRow(prev)) {
|
||||
const topRow = prev as TopRow;
|
||||
if (
|
||||
!topRow.hasPreviousConnection &&
|
||||
!prev.hasPreviousConnection &&
|
||||
(!this.outputConnection || this.hasStatementInput)
|
||||
) {
|
||||
return Math.abs(
|
||||
@@ -219,7 +217,6 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
return this.constants_.NO_PADDING;
|
||||
}
|
||||
if (Types.isBottomRow(next)) {
|
||||
const bottomRow = next as BottomRow;
|
||||
if (!this.outputConnection) {
|
||||
const topHeight =
|
||||
Math.max(
|
||||
@@ -230,7 +227,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
),
|
||||
) - this.constants_.CORNER_RADIUS;
|
||||
return topHeight;
|
||||
} else if (!bottomRow.hasNextConnection && this.hasStatementInput) {
|
||||
} else if (!next.hasNextConnection && this.hasStatementInput) {
|
||||
return Math.abs(
|
||||
this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS,
|
||||
);
|
||||
@@ -259,7 +256,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
) {
|
||||
return row.yPos + this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT / 2;
|
||||
}
|
||||
if (Types.isInlineInput(elem) && elem instanceof InputConnection) {
|
||||
if (Types.isInlineInput(elem)) {
|
||||
const connectedBlock = elem.connectedBlock;
|
||||
if (
|
||||
connectedBlock &&
|
||||
@@ -308,7 +305,6 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
}
|
||||
if (
|
||||
Types.isField(elem) &&
|
||||
elem instanceof Field &&
|
||||
elem.parentInput === this.rightAlignedDummyInputs.get(row)
|
||||
) {
|
||||
break;
|
||||
@@ -371,7 +367,6 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
xCursor < minXPos &&
|
||||
!(
|
||||
Types.isField(elem) &&
|
||||
elem instanceof Field &&
|
||||
(elem.field instanceof FieldLabel ||
|
||||
elem.field instanceof FieldImage)
|
||||
)
|
||||
@@ -525,7 +520,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (Types.isInlineInput(elem) && elem instanceof InputConnection) {
|
||||
if (Types.isInlineInput(elem)) {
|
||||
const connectedBlock = elem.connectedBlock;
|
||||
const innerShape = connectedBlock
|
||||
? (connectedBlock.pathObject as PathObject).outputShapeType
|
||||
@@ -552,7 +547,7 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
connectionWidth -
|
||||
this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][innerShape]
|
||||
);
|
||||
} else if (Types.isField(elem) && elem instanceof Field) {
|
||||
} else if (Types.isField(elem)) {
|
||||
// Special case for text inputs.
|
||||
if (
|
||||
outerShape === constants.SHAPES.ROUND &&
|
||||
@@ -616,7 +611,6 @@ export class RenderInfo extends BaseRenderInfo {
|
||||
for (let j = 0; j < row.elements.length; j++) {
|
||||
const elem = row.elements[j];
|
||||
if (
|
||||
elem instanceof InputConnection &&
|
||||
Types.isInlineInput(elem) &&
|
||||
elem.connectedBlock &&
|
||||
!elem.connectedBlock.isShadow() &&
|
||||
|
||||
Reference in New Issue
Block a user