Zelos horizontal tight nesting. (#3490)

* Reduce the amount of implicit spacing added by the connection shape by adding negative spacing to the first and last spacer in an output block
This commit is contained in:
Sam El-Husseini
2019-12-06 10:51:50 -08:00
committed by GitHub
parent 55997784ca
commit f5bb5b6143
6 changed files with 182 additions and 19 deletions

View File

@@ -430,13 +430,21 @@ Blockly.blockRendering.ConstantProvider = function() {
*/
this.CURSOR_STROKE_WIDTH = 4;
/*
/**
* Whether text input and colour fields fill up the entire source block.
* @type {boolean}
* @package
*/
this.FULL_BLOCK_FIELDS = false;
/**
* Enum for connection shapes.
* @enum {number}
*/
this.SHAPES = {
PUZZLE: 1,
NOTCH: 2
};
};
/**
@@ -717,6 +725,7 @@ Blockly.blockRendering.ConstantProvider.prototype.makePuzzleTab = function() {
var pathDown = makeMainPath(false);
return {
type: this.SHAPES.PUZZLE,
width: width,
height: height,
pathDown: pathDown,
@@ -746,6 +755,7 @@ Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() {
var pathRight = makeMainPath(-1);
return {
type: this.SHAPES.NOTCH,
width: width,
height: height,
pathLeft: pathLeft,

View File

@@ -121,6 +121,11 @@ Blockly.blockRendering.Debug.prototype.drawSpacerElem = function(elem, rowHeight
return;
}
// Don't render elements with negative spacing.
if (elem.width < 0) {
return;
}
var xPos = elem.xPos;
if (isRtl) {
xPos = -(xPos + elem.width);

View File

@@ -159,6 +159,47 @@ Blockly.zelos.ConstantProvider = function() {
*/
this.CURSOR_RADIUS = 5;
/**
* @enum {number}
* @override
*/
this.SHAPES = {
HEXAGONAL: 1,
ROUND: 2,
SQUARE: 3,
PUZZLE: 4,
NOTCH: 5
};
/**
* Map of output/input shapes and the amount they should cause a block to be
* padded. Outer key is the outer shape, inner key is the inner shape.
* When a block with the outer shape contains an input block with the inner
* shape on its left or right edge, the block elements are aligned such that
* the padding specified is reached.
* @package
*/
this.SHAPE_IN_SHAPE_PADDING = {
1: { // Outer shape: hexagon.
0: 5 * this.GRID_UNIT, // Field in hexagon.
1: 2 * this.GRID_UNIT, // Hexagon in hexagon.
2: 5 * this.GRID_UNIT, // Round in hexagon.
3: 5 * this.GRID_UNIT // Square in hexagon.
},
2: { // Outer shape: round.
0: 3 * this.GRID_UNIT, // Field in round.
1: 3 * this.GRID_UNIT, // Hexagon in round.
2: 1 * this.GRID_UNIT, // Round in round.
3: 2 * this.GRID_UNIT // Square in round.
},
3: { // Outer shape: square.
0: 2 * this.GRID_UNIT, // Field in square.
1: 2 * this.GRID_UNIT, // Hexagon in square.
2: 2 * this.GRID_UNIT, // Round in square.
3: 2 * this.GRID_UNIT // Square in square.
}
};
/**
* @override
*/
@@ -348,6 +389,7 @@ Blockly.zelos.ConstantProvider.prototype.makeHexagonal = function() {
}
return {
type: this.SHAPES.HEXAGONAL,
isDynamic: true,
width: function(height) {
return height / 2;
@@ -386,6 +428,7 @@ Blockly.zelos.ConstantProvider.prototype.makeRounded = function() {
}
return {
type: this.SHAPES.ROUND,
isDynamic: true,
width: function(height) {
return height / 2;
@@ -499,6 +542,7 @@ Blockly.zelos.ConstantProvider.prototype.makeNotch = function() {
var pathRight = makeMainPath(-1);
return {
type: this.SHAPES.NOTCH,
width: width,
height: height,
pathLeft: pathLeft,

View File

@@ -67,6 +67,11 @@ Blockly.zelos.Drawer.prototype.draw = function() {
this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
}
this.recordSizeOnBlock_();
if (this.info_.outputConnection) {
// Store the output connection shape type for parent blocks to use during
// rendering.
pathObject.outputShapeType = this.info_.outputConnection.shape.type;
}
pathObject.endDrawing();
};

View File

@@ -253,39 +253,130 @@ Blockly.zelos.RenderInfo.prototype.adjustXPosition_ = function() {
};
/**
* Finalize the output connection info. In particular set the height of the
* Finalize the output connection info. In particular, set the height of the
* output connection to match that of the block. For the right side, add a
* right connection shape element and have it match the dimensions of the
* output connection.
* @protected
*/
Blockly.zelos.RenderInfo.prototype.finalizeOutputConnection_ = function() {
// Dynamic output connections depend on the height of the block.
if (!this.outputConnection || !this.outputConnection.isDynamicShape) {
return;
}
var yCursor = 0;
// Determine the block height.
for (var i = 0, row; (row = this.rows[i]); i++) {
row.yPos = yCursor;
yCursor += row.height;
}
if (this.outputConnection && this.outputConnection.isDynamicShape) {
// Dynamic output connections depend on the height of the block. Adjust the
// height of the connection.
var connectionHeight = this.outputConnection.shape.height(yCursor);
var connectionWidth = this.outputConnection.shape.width(yCursor);
this.outputConnection.height = connectionHeight;
this.outputConnection.width = connectionWidth;
this.outputConnection.startX = connectionWidth;
// Adjust the height of the output connection.
var connectionHeight = this.outputConnection.shape.height(yCursor);
var connectionWidth = this.outputConnection.shape.width(yCursor);
// Adjust right side measurable.
this.rightSide.height = connectionHeight;
this.rightSide.width = connectionWidth;
this.rightSide.centerline = connectionHeight / 2;
this.rightSide.xPos = this.width + connectionWidth;
this.outputConnection.height = connectionHeight;
this.outputConnection.width = connectionWidth;
this.outputConnection.startX = connectionWidth;
this.startX = connectionWidth;
this.width += connectionWidth * 2;
this.widthWithChildren += connectionWidth * 2;
// Adjust right side measurable.
this.rightSide.height = connectionHeight;
this.rightSide.width = connectionWidth;
this.rightSide.centerline = connectionHeight / 2;
this.rightSide.xPos = this.width + connectionWidth;
this.startX = connectionWidth;
this.width += connectionWidth * 2;
this.widthWithChildren += connectionWidth * 2;
};
/**
* Finalize alignment of elements on the block. In particular, reduce the
* implicit spacing created by the left and right output connection shapes by
* adding setting negative spacing onto the leftmost and rightmost spacers.
* @protected
*/
Blockly.zelos.RenderInfo.prototype.finalizeAlignment_ = function() {
if (!this.outputConnection) {
return;
}
var totalNegativeSpacing = 0;
for (var i = 0, row; (row = this.rows[i]); i++) {
if (!Blockly.blockRendering.Types.isInputRow(row)) {
continue;
}
var firstElem = row.elements[1];
var lastElem = row.elements[row.elements.length - 2];
var leftNegPadding = this.getNegativeSpacing_(firstElem);
var rightNegPadding = this.getNegativeSpacing_(lastElem);
totalNegativeSpacing = leftNegPadding + rightNegPadding;
var minBlockWidth = this.constants_.MIN_BLOCK_WIDTH +
this.outputConnection.width * 2;
if (this.width - totalNegativeSpacing < minBlockWidth) {
// Maintain a minimum block width, split negative spacing between left
// and right edge.
totalNegativeSpacing = this.width - minBlockWidth;
row.getFirstSpacer().width = -totalNegativeSpacing / 2;
row.getLastSpacer().width = -totalNegativeSpacing / 2;
} else {
row.getFirstSpacer().width = -leftNegPadding;
row.getLastSpacer().width = -rightNegPadding;
}
}
if (totalNegativeSpacing) {
this.width -= totalNegativeSpacing;
this.widthWithChildren -= totalNegativeSpacing;
this.rightSide.xPos -= totalNegativeSpacing;
for (var i = 0, row; (row = this.rows[i]); i++) {
if (Blockly.blockRendering.Types.isTopRow(row) ||
Blockly.blockRendering.Types.isBottomRow(row)) {
row.elements[1].width -= totalNegativeSpacing;
}
row.width -= totalNegativeSpacing;
row.widthWithConnectedBlocks -= totalNegativeSpacing;
}
}
};
/**
* Calculate the spacing to reduce the left and right edges by based on the
* outer and inner connection shape.
* @param {Blockly.blockRendering.Measurable} elem The first or last element on
* a block.
* @return {number} The amount of spacing to reduce the first or last spacer.
* @protected
*/
Blockly.zelos.RenderInfo.prototype.getNegativeSpacing_ = function(elem) {
if (!elem) {
return 0;
}
var connectionWidth = this.outputConnection.width;
var outerShape = this.outputConnection.shape.type;
var constants =
/** @type {!Blockly.zelos.ConstantProvider} */ (this.constants_);
if (Blockly.blockRendering.Types.isInlineInput(elem)) {
var innerShape = elem.connectedBlock ?
elem.connectedBlock.pathObject.outputShapeType :
elem.shape.type;
// Special case for hexagonal output.
if (outerShape == constants.SHAPES.HEXAGONAL &&
outerShape != innerShape) {
return 0;
}
return connectionWidth -
this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][innerShape];
} else if (Blockly.blockRendering.Types.isField(elem)) {
// Special case for text inputs.
if (outerShape == constants.SHAPES.ROUND &&
elem.field instanceof Blockly.FieldTextInput) {
return connectionWidth - (2.75 * constants.GRID_UNIT);
}
return connectionWidth -
this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][0];
} else if (Blockly.blockRendering.Types.isIcon(elem)) {
return this.constants_.SMALL_PADDING;
}
return 0;
};
/**
@@ -293,5 +384,6 @@ Blockly.zelos.RenderInfo.prototype.finalizeOutputConnection_ = function() {
*/
Blockly.zelos.RenderInfo.prototype.finalize_ = function() {
this.finalizeOutputConnection_();
this.finalizeAlignment_();
Blockly.zelos.RenderInfo.superClass_.finalize_.call(this);
};

View File

@@ -74,6 +74,13 @@ Blockly.zelos.PathObject = function(root, style, constants) {
* @private
*/
this.remainingOutlines_ = null;
/**
* The type of block's output connection shape. This is set when a block with
* an output connection is drawn.
* @package
*/
this.outputShapeType = null;
};
Blockly.utils.object.inherits(Blockly.zelos.PathObject,
Blockly.blockRendering.PathObject);