diff --git a/core/renderers/common/debugger.js b/core/renderers/common/debugger.js index f2739d804..3e0da16b2 100644 --- a/core/renderers/common/debugger.js +++ b/core/renderers/common/debugger.js @@ -238,7 +238,7 @@ Blockly.blockRendering.Debug.prototype.drawRenderedRow = function(row, cursorY, { 'class': 'elemRenderingRect blockRenderDebug', 'x': isRtl ? -(row.xPos + row.width) : row.xPos, - 'y': cursorY, + 'y': row.yPos, 'width': row.width, 'height': row.height, 'stroke': 'red', @@ -256,7 +256,7 @@ Blockly.blockRendering.Debug.prototype.drawRenderedRow = function(row, cursorY, { 'class': 'connectedBlockWidth blockRenderDebug', 'x': isRtl ? -(row.xPos + row.widthWithConnectedBlocks) : row.xPos, - 'y': cursorY, + 'y': row.yPos, 'width': row.widthWithConnectedBlocks, 'height': row.height, 'stroke': this.randomColour_, diff --git a/core/renderers/common/drawer.js b/core/renderers/common/drawer.js index 2cb9021d0..76e6fa461 100644 --- a/core/renderers/common/drawer.js +++ b/core/renderers/common/drawer.js @@ -239,7 +239,7 @@ Blockly.blockRendering.Drawer.prototype.drawBottom_ = function() { this.positionNextConnection_(); this.outlinePath_ += - Blockly.utils.svgPaths.lineOnAxis('v', bottomRow.height - bottomRow.overhangY); + Blockly.utils.svgPaths.lineOnAxis('V', bottomRow.baseline); for (var i = elems.length - 1, elem; (elem = elems[i]); i--) { if (Blockly.blockRendering.Types.isNextConnection(elem)) { diff --git a/core/renderers/common/info.js b/core/renderers/common/info.js index a7649a1a1..c153b6089 100644 --- a/core/renderers/common/info.js +++ b/core/renderers/common/info.js @@ -492,20 +492,19 @@ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowHeight_ = function( /** * Calculate the centerline of an element in a rendered row. + * This base implementation puts the centerline at the middle of the row + * vertically, with no special cases. You will likely need extra logic to + * handle (at minimum) top and bottom rows. * @param {!Blockly.blockRendering.Row} row The row containing the element. - * @param {!Blockly.blockRendering.Measurable} elem The element to place. + * @param {!Blockly.blockRendering.Measurable} _elem The element to place. * @return {number} The desired centerline of the given element, as an offset * from the top left of the block. * @protected */ Blockly.blockRendering.RenderInfo.prototype.getElemCenterline_ = function(row, - elem) { + _elem) { var result = row.yPos; - if (Blockly.blockRendering.Types.isNextConnection(elem)) { - result += (row.height - row.overhangY + elem.height / 2); - } else { - result += (row.height / 2); - } + result += (row.height / 2); return result; }; @@ -538,5 +537,6 @@ Blockly.blockRendering.RenderInfo.prototype.finalize_ = function() { this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; this.height = yCursor; - this.startY = this.topRow.startY; + this.startY = this.topRow.capline; + this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight; }; diff --git a/core/renderers/geras/highlighter.js b/core/renderers/geras/highlighter.js index a60c019d5..9f5c50799 100644 --- a/core/renderers/geras/highlighter.js +++ b/core/renderers/geras/highlighter.js @@ -172,21 +172,21 @@ Blockly.geras.Highlighter.prototype.drawRightSideRow = function(row) { }; Blockly.geras.Highlighter.prototype.drawBottomRow = function(row) { - var height = row.yPos + row.height - row.overhangY; + var baseline = row.baseline; // Highlight the vertical edge of the bottom row on the input side. // Highlighting is always from the top left, both in LTR and RTL. if (this.RTL_) { - this.steps_.push('V', height - this.highlightOffset_); + this.steps_.push('V', baseline - this.highlightOffset_); } else { var cornerElem = this.info_.bottomRow.elements[0]; if (Blockly.blockRendering.Types.isLeftSquareCorner(cornerElem)) { this.steps_.push( Blockly.utils.svgPaths.moveTo( row.xPos + this.highlightOffset_, - height - this.highlightOffset_)); + baseline - this.highlightOffset_)); } else if (Blockly.blockRendering.Types.isLeftRoundedCorner(cornerElem)) { - this.steps_.push(Blockly.utils.svgPaths.moveTo(row.xPos, height)); + this.steps_.push(Blockly.utils.svgPaths.moveTo(row.xPos, baseline)); this.steps_.push(this.outsideCornerPaths_.bottomLeft()); } } @@ -214,7 +214,7 @@ Blockly.geras.Highlighter.prototype.drawLeft = function() { if (Blockly.blockRendering.Types.isLeftRoundedCorner(topRow.elements[0])) { this.steps_.push('V', this.outsideCornerPaths_.height); } else { - this.steps_.push('V', topRow.startY + this.highlightOffset_); + this.steps_.push('V', topRow.capline + this.highlightOffset_); } } }; diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js index 53322a32d..7a8cedcfd 100644 --- a/core/renderers/geras/info.js +++ b/core/renderers/geras/info.js @@ -296,6 +296,21 @@ Blockly.geras.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { * @override */ Blockly.geras.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { + if (Blockly.blockRendering.Types.isBottomRow(row)) { + var baseline = row.yPos + row.height - row.descenderHeight; + if (Blockly.blockRendering.Types.isNextConnection(elem)) { + return baseline + elem.height / 2; + } + return baseline - elem.height / 2; + } + if (Blockly.blockRendering.Types.isTopRow(row)) { + var capline = row.capline; + if (Blockly.blockRendering.Types.isHat(elem)) { + return capline - elem.height / 2; + } + return capline + elem.height / 2; + } + var result = row.yPos; if (Blockly.blockRendering.Types.isField(elem) || Blockly.blockRendering.Types.isIcon(elem)) { @@ -306,7 +321,7 @@ Blockly.geras.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { } else if (Blockly.blockRendering.Types.isInlineInput(elem)) { result += elem.height / 2; } else if (Blockly.blockRendering.Types.isNextConnection(elem)) { - result += (row.height - row.overhangY + elem.height / 2); + result += (row.height - row.descenderHeight + elem.height / 2); } else { result += (row.height / 2); } @@ -330,7 +345,7 @@ Blockly.geras.RenderInfo.prototype.finalize_ = function() { widestRowWithConnectedBlocks = Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); // Add padding to the bottom row if block height is less than minimum - var heightWithoutHat = yCursor - this.topRow.startY; + var heightWithoutHat = yCursor - this.topRow.ascenderHeight; if (row == this.bottomRow && heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) { // But the hat height shouldn't be part of this. @@ -345,9 +360,10 @@ Blockly.geras.RenderInfo.prototype.finalize_ = function() { xCursor += elem.width; } } + this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight; this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; this.height = yCursor; - this.startY = this.topRow.startY; + this.startY = this.topRow.capline; }; diff --git a/core/renderers/measurables/row_elements.js b/core/renderers/measurables/row_elements.js index 07bf6f944..e236b5a1b 100644 --- a/core/renderers/measurables/row_elements.js +++ b/core/renderers/measurables/row_elements.js @@ -82,7 +82,7 @@ Blockly.blockRendering.Hat = function() { this.type |= Blockly.blockRendering.Types.HAT; this.height = this.constants_.START_HAT.height; this.width = this.constants_.START_HAT.width; - this.startY = this.height; + this.ascenderHeight = this.height; }; goog.inherits(Blockly.blockRendering.Hat, Blockly.blockRendering.Measurable); @@ -101,7 +101,7 @@ Blockly.blockRendering.SquareCorner = function(opt_position) { Blockly.blockRendering.Types.LEFT_SQUARE_CORNER : Blockly.blockRendering.Types.RIGHT_SQUARE_CORNER) | Blockly.blockRendering.Types.CORNER; - this.height = this.constants_.NOTCH.height; + this.height = this.constants_.NO_PADDING; this.width = this.constants_.NO_PADDING; }; @@ -125,7 +125,7 @@ Blockly.blockRendering.RoundCorner = function(opt_position) { 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_.NOTCH.height; + this.height = this.constants_.CORNER_RADIUS / 2; }; goog.inherits(Blockly.blockRendering.RoundCorner, diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index 6a3b08d3e..65066f408 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -227,7 +227,9 @@ Blockly.blockRendering.TopRow = function() { * @package * @type {number} */ - this.startY = 0; + this.capline = 0; + + this.ascenderHeight = 0; /** * Whether the block has a previous connection. @@ -263,7 +265,7 @@ Blockly.blockRendering.TopRow.prototype.populate = function(block) { if (hasHat) { var hat = new Blockly.blockRendering.Hat(); this.elements.push(hat); - this.startY = hat.startY; + this.capline = hat.ascenderHeight; } else if (hasPrevious) { this.hasPreviousConnection = true; this.connection = new Blockly.blockRendering.PreviousConnection( @@ -300,18 +302,23 @@ Blockly.blockRendering.TopRow.prototype.hasLeftSquareCorner = function(block) { * @override */ Blockly.blockRendering.TopRow.prototype.measure = function() { - this.width = this.minWidth; - this.height = this.minHeight; + var height = 0; + var width = 0; + var ascenderHeight = 0; for (var e = 0, elem; (elem = this.elements[e]); e++) { - this.width += elem.width; + width += elem.width; if (!(Blockly.blockRendering.Types.isSpacer(elem))) { if (Blockly.blockRendering.Types.isHat(elem)) { - this.startY = elem.startY; - this.height = this.height + elem.height; + ascenderHeight = Math.max(ascenderHeight, elem.ascenderHeight); + } else { + height = Math.max(height, elem.height); } - this.height = Math.max(this.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; }; @@ -347,7 +354,9 @@ Blockly.blockRendering.BottomRow = function() { * @package * @type {number} */ - this.overhangY = 0; + this.descenderHeight = 0; + + this.baseline = 0; }; goog.inherits(Blockly.blockRendering.BottomRow, Blockly.blockRendering.Row); @@ -368,7 +377,7 @@ Blockly.blockRendering.BottomRow.prototype.populate = function(block) { if (followsStatement) { this.minHeight = this.constants_.LARGE_PADDING; } else { - this.minHeight = this.constants_.NOTCH.height; + this.minHeight = this.constants_.MEDIUM_PADDING - 1; } var leftSquareCorner = this.hasLeftSquareCorner(block); @@ -400,18 +409,24 @@ Blockly.blockRendering.BottomRow.prototype.hasLeftSquareCorner = function( * @override */ Blockly.blockRendering.BottomRow.prototype.measure = function() { - this.width = this.minWidth; - this.height = this.minHeight; + var height = 0; + var width = 0; + var descenderHeight = 0; for (var e = 0, elem; (elem = this.elements[e]); e++) { - this.width += elem.width; + width += elem.width; if (!(Blockly.blockRendering.Types.isSpacer(elem))) { + // Note: this assumes that next connections have *only* descenderHeight, + // with no height above the baseline. if (Blockly.blockRendering.Types.isNextConnection(elem)) { - this.height = this.height + elem.height; - this.overhangY = elem.height; + descenderHeight = Math.max(descenderHeight, elem.height); + } else { + height = Math.max(height, elem.height); } - this.height = Math.max(this.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; }; /** diff --git a/core/renderers/thrasos/info.js b/core/renderers/thrasos/info.js index 69dacc466..49bbc9b3f 100644 --- a/core/renderers/thrasos/info.js +++ b/core/renderers/thrasos/info.js @@ -297,13 +297,28 @@ Blockly.thrasos.RenderInfo.prototype.getSpacerRowHeight_ = function( * @override */ Blockly.thrasos.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { + if (Blockly.blockRendering.Types.isBottomRow(row)) { + var baseline = row.yPos + row.height - row.descenderHeight; + if (Blockly.blockRendering.Types.isNextConnection(elem)) { + return baseline + elem.height / 2; + } + return baseline - elem.height / 2; + } + if (Blockly.blockRendering.Types.isTopRow(row)) { + var capline = row.capline; + if (Blockly.blockRendering.Types.isHat(elem)) { + return capline - elem.height / 2; + } + return capline + elem.height / 2; + } + var result = row.yPos; if (Blockly.blockRendering.Types.isField(elem) && row.hasStatement) { var offset = this.constants_.TALL_INPUT_FIELD_OFFSET_Y + elem.height / 2; result += offset; } else if (Blockly.blockRendering.Types.isNextConnection(elem)) { - result += (row.height - row.overhangY + elem.height / 2); + result += (row.height - row.descenderHeight + elem.height / 2); } else { result += (row.height / 2); } @@ -327,7 +342,7 @@ Blockly.thrasos.RenderInfo.prototype.finalize_ = function() { widestRowWithConnectedBlocks = Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); // Add padding to the bottom row if block height is less than minimum - var heightWithoutHat = yCursor - this.topRow.startY; + var heightWithoutHat = yCursor - this.topRow.ascenderHeight; if (row == this.bottomRow && heightWithoutHat < this.constants_.MIN_BLOCK_HEIGHT) { // But the hat height shouldn't be part of this. @@ -343,8 +358,9 @@ Blockly.thrasos.RenderInfo.prototype.finalize_ = function() { } } + this.bottomRow.baseline = yCursor - this.bottomRow.descenderHeight; this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; this.height = yCursor; - this.startY = this.topRow.startY; + this.startY = this.topRow.capline; }; diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 3684410bc..c4ab78419 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -91,7 +91,7 @@ Blockly.zelos.Drawer.prototype.drawBottom_ = function() { this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis('v', - bottomRow.height - bottomRow.overhangY - + bottomRow.height - bottomRow.descenderHeight - this.constants_.INSIDE_CORNERS.rightHeight); for (var i = elems.length - 1, elem; (elem = elems[i]); i--) { diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index fb38791c6..cdae2c1e4 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -283,6 +283,35 @@ Blockly.zelos.RenderInfo.prototype.getSpacerRowHeight_ = function( return this.constants_.MEDIUM_PADDING; }; +/** + * @override + */ +Blockly.zelos.RenderInfo.prototype.getElemCenterline_ = function(row, + elem) { + if (Blockly.blockRendering.Types.isBottomRow(row)) { + var baseline = row.yPos + row.height - row.descenderHeight; + if (Blockly.blockRendering.Types.isNextConnection(elem)) { + return baseline + elem.height / 2; + } + return baseline - elem.height / 2; + } + if (Blockly.blockRendering.Types.isTopRow(row)) { + var capline = row.capline; + if (Blockly.blockRendering.Types.isHat(elem)) { + return capline - elem.height / 2; + } + return capline + elem.height / 2; + } + + var result = row.yPos; + if (Blockly.blockRendering.Types.isNextConnection(elem)) { + result += (row.height - row.descenderHeight + elem.height / 2); + } else { + result += (row.height / 2); + } + return result; +}; + /** * Modify the given row to add the given amount of padding around its fields. * The exact location of the padding is based on the alignment property of the