diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index ee84553e6..c9a62a044 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -103,15 +103,18 @@ goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/ goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_render_draw_debug.js", ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Highlighter', 'Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_render_draw_highlight.js", ['Blockly.blockRendering.Highlighter'], ['Blockly.blockRendering.highlightConstants', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_render_info.js", ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.RenderedConnection']); -goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.RenderInfo']); +goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.RenderInfo', 'Blockly.geras.RenderInfo', 'Blockly.thrasos.RenderInfo', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/block_rendering_constants.js", ['Blockly.blockRendering.constants'], ['Blockly.utils.svgPaths']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/highlight_constants.js", ['Blockly.blockRendering.highlightConstants'], ['Blockly.blockRendering.constants', 'Blockly.utils.svgPaths']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/measurables.js", ['Blockly.blockRendering.InRowSpacer'], ['Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable']); goog.addDependency("../../../" + dir + "/core/renderers/block_rendering_rewrite/shape_map.js", ['Blockly.blockRendering.connectionShapes'], ['Blockly.RenderedConnection']); +goog.addDependency("../../../" + dir + "/core/renderers/geras/info.js", ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/renderers/measurables/base.js", ['Blockly.blockRendering.Measurable'], ['Blockly.blockRendering.constants']); goog.addDependency("../../../" + dir + "/core/renderers/measurables/connections.js", ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.constants', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/renderers/measurables/inputs.js", ['Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.ExternalValueInput'], ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.constants']); goog.addDependency("../../../" + dir + "/core/renderers/measurables/rows.js", ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow'], ['Blockly.blockRendering.constants', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.RenderedConnection']); +goog.addDependency("../../../" + dir + "/core/renderers/thrasos/info.js", ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.RenderedConnection']); +goog.addDependency("../../../" + dir + "/core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.constants', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/theme.js", ['Blockly.Theme'], []); goog.addDependency("../../../" + dir + "/core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); @@ -1926,8 +1929,12 @@ goog.require('Blockly.blockRendering.constants'); goog.require('Blockly.blockRendering.highlightConstants'); goog.require('Blockly.constants'); goog.require('Blockly.fieldRegistry'); +goog.require('Blockly.geras'); +goog.require('Blockly.geras.RenderInfo'); goog.require('Blockly.inject'); goog.require('Blockly.navigation'); +goog.require('Blockly.thrasos'); +goog.require('Blockly.thrasos.RenderInfo'); goog.require('Blockly.tree.BaseNode'); goog.require('Blockly.tree.TreeControl'); goog.require('Blockly.tree.TreeNode'); @@ -1949,6 +1956,8 @@ goog.require('Blockly.utils.svgPaths'); goog.require('Blockly.utils.uiMenu'); goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils.xml'); +goog.require('Blockly.zelos'); +goog.require('Blockly.zelos.RenderInfo'); delete root.BLOCKLY_DIR; delete root.BLOCKLY_BOOT; diff --git a/core/renderers/block_rendering_rewrite/block_render_info.js b/core/renderers/block_rendering_rewrite/block_render_info.js index dda37996f..24c31baed 100644 --- a/core/renderers/block_rendering_rewrite/block_render_info.js +++ b/core/renderers/block_rendering_rewrite/block_render_info.js @@ -158,7 +158,7 @@ Blockly.blockRendering.RenderInfo = function(block) { * may choose to rerender when getSize() is called). However, calling it * repeatedly may be expensive. * - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.measure_ = function() { this.createRows_(); @@ -172,7 +172,7 @@ Blockly.blockRendering.RenderInfo.prototype.measure_ = function() { /** * Create rows of Measurable objects representing all renderable parts of the * block. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() { this.topRow.populate(this.block_); @@ -231,7 +231,7 @@ Blockly.blockRendering.RenderInfo.prototype.createRows_ = function() { * @param {!Blockly.Input} input The input to record information about. * @param {!Blockly.blockRendering.Row} activeRow The row that is currently being * populated. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRow) { // Non-dummy inputs have visual representations onscreen. @@ -256,7 +256,7 @@ Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRo * @param {!Blockly.Input} input The first input to consider * @param {Blockly.Input} lastInput The input that follows. * @return {boolean} True if the next input should be rendered on a new row. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) { // If this is the first input, just add to the existing row. @@ -277,7 +277,7 @@ Blockly.blockRendering.RenderInfo.prototype.shouldStartNewRow_ = function(input, /** * Add horizontal spacing between and around elements within each row. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.addElemSpacing_ = function() { for (var i = 0, row; (row = this.rows[i]); i++) { @@ -305,56 +305,11 @@ Blockly.blockRendering.RenderInfo.prototype.addElemSpacing_ = function() { * spacer. * @param {Blockly.blockRendering.Measurable} next The element after the spacer. * @return {number} The size of the spacing between the two elements. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { - if (!prev) { - // Between an editable field and the beginning of the row. - if (next.isField() && next.isEditable) { - return Blockly.blockRendering.constants.MEDIUM_PADDING; - } - // Inline input at the beginning of the row. - if (next.isInput && next.isInlineInput()) { - return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; - } - if (next.isStatementInput()) { - return Blockly.blockRendering.constants.STATEMENT_INPUT_PADDING_LEFT; - } - // Anything else at the beginning of the row. - return Blockly.blockRendering.constants.LARGE_PADDING; - } - - // Spacing between a non-input and the end of the row. - if (!prev.isInput && !next) { - // Between an editable field and the end of the row. - if (prev.isField() && prev.isEditable) { - return Blockly.blockRendering.constants.MEDIUM_PADDING; - } - // Padding at the end of an icon-only row to make the block shape clearer. - if (prev.isIcon()) { - return (Blockly.blockRendering.constants.LARGE_PADDING * 2) + 1; - } - if (prev.isHat()) { - return Blockly.blockRendering.constants.NO_PADDING; - } - // Establish a minimum width for a block with a previous or next connection. - if (prev.isPreviousConnection() || prev.isNextConnection()) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - // Between rounded corner and the end of the row. - if (prev.isRoundedCorner()) { - return Blockly.blockRendering.constants.MIN_BLOCK_WIDTH; - } - // Between a jagged edge and the end of the row. - if (prev.isJaggedEdge()) { - return Blockly.blockRendering.constants.NO_PADDING; - } - // Between noneditable fields and icons and the end of the row. - return Blockly.blockRendering.constants.LARGE_PADDING; - } - // Between inputs and the end of the row. - if (prev.isInput && !next) { + if (prev && prev.isInput && !next) { if (prev.isExternalInput()) { return Blockly.blockRendering.constants.NO_PADDING; } else if (prev.isInlineInput()) { @@ -364,83 +319,6 @@ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, ne } } - // Spacing between a non-input and an input. - if (!prev.isInput && next.isInput) { - // Between an editable field and an input. - if (prev.isEditable) { - if (next.isInlineInput()) { - return Blockly.blockRendering.constants.SMALL_PADDING; - } else if (next.isExternalInput()) { - return Blockly.blockRendering.constants.SMALL_PADDING; - } - } else { - if (next.isInlineInput()) { - return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; - } else if (next.isExternalInput()) { - return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; - } else if (next.isStatementInput()) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - } - return Blockly.blockRendering.constants.LARGE_PADDING - 1; - } - - // Spacing between an icon and an icon or field. - if (prev.isIcon() && !next.isInput) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - - // Spacing between an inline input and a field. - if (prev.isInlineInput() && !next.isInput) { - // Editable field after inline input. - if (next.isEditable) { - return Blockly.blockRendering.constants.MEDIUM_PADDING; - } else { - // Noneditable field after inline input. - return Blockly.blockRendering.constants.LARGE_PADDING; - } - } - - if (prev.isSquareCorner()) { - // Spacing between a hat and a corner - if (next.isHat()) { - return Blockly.blockRendering.constants.NO_PADDING; - } - // Spacing between a square corner and a previous or next connection - if (next.isPreviousConnection()) { - return next.notchOffset; - } else if (next.isNextConnection()) { - // Next connections are shifted slightly to the left (in both LTR and RTL) - // to make the dark path under the previous connection show through. - var offset = (this.RTL ? 1 : -1) * - Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; - return next.notchOffset + offset; - } - } - - // Spacing between a rounded corner and a previous or next connection. - if (prev.isRoundedCorner()) { - if (next.isPreviousConnection()) { - return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS; - } else if (next.isNextConnection()) { - // Next connections are shifted slightly to the left (in both LTR and RTL) - // to make the dark path under the previous connection show through. - var offset = (this.RTL ? 1 : -1) * - Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; - return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS + offset; - } - } - - // Spacing between two fields of the same editability. - if (!prev.isInput && !next.isInput && (prev.isEditable == next.isEditable)) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - - // Spacing between anything and a jagged edge. - if (next.isJaggedEdge()) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - return Blockly.blockRendering.constants.MEDIUM_PADDING; }; @@ -448,7 +326,7 @@ Blockly.blockRendering.RenderInfo.prototype.getInRowSpacing_ = function(prev, ne * Figure out where the right edge of the block and right edge of statement inputs * should be placed. * TODO: More cleanup. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() { var widestStatementRowFields = 0; @@ -490,7 +368,7 @@ Blockly.blockRendering.RenderInfo.prototype.computeBounds_ = function() { * Extra spacing may be necessary to make sure that the right sides of all * rows line up. This can only be calculated after a first pass to calculate * the sizes of all rows. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.alignRowElements_ = function() { for (var i = 0, row; (row = this.rows[i]); i++) { @@ -503,9 +381,6 @@ Blockly.blockRendering.RenderInfo.prototype.alignRowElements_ = function() { var currentWidth = row.width; var desiredWidth = this.width - this.startX; } - if (row.type == 'bottom row' && row.hasFixedWidth) { - desiredWidth = Blockly.blockRendering.constants.MAX_BOTTOM_WIDTH; - } var missingSpace = desiredWidth - currentWidth; if (missingSpace) { this.addAlignmentPadding_(row, missingSpace); @@ -520,42 +395,19 @@ Blockly.blockRendering.RenderInfo.prototype.alignRowElements_ = function() { * last input in the field. * @param {Blockly.blockRendering.Row} row The row to add padding to. * @param {number} missingSpace How much padding to add. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) { - var elems = row.elements; - var input = row.getLastInput(); - if (input) { - var firstSpacer = row.getFirstSpacer(); - var lastSpacer = row.getLastSpacer(); - if (row.hasExternalInput || row.hasStatement) { - // Get the spacer right before the input socket. - lastSpacer = elems[elems.length - 3]; - row.widthWithConnectedBlocks += missingSpace; - } - // Decide where the extra padding goes. - if (input.align == Blockly.ALIGN_LEFT) { - // Add padding to the end of the row. - lastSpacer.width += missingSpace; - } else if (input.align == Blockly.ALIGN_CENTRE) { - // Split the padding between the beginning and end of the row. - firstSpacer.width += missingSpace / 2; - lastSpacer.width += missingSpace / 2; - } else if (input.align == Blockly.ALIGN_RIGHT) { - // Add padding at the beginning of the row. - firstSpacer.width += missingSpace; - } - row.width += missingSpace; - // Top and bottom rows are always left aligned. - } else if (row.type == 'top row' || row.type == 'bottom row') { - row.getLastSpacer().width += missingSpace; + var lastSpacer = row.getLastSpacer(); + if (lastSpacer) { + lastSpacer.width += missingSpace; row.width += missingSpace; } }; /** * Add spacers between rows and set their sizes. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.addRowSpacing_ = function() { var oldRows = this.rows; @@ -574,7 +426,7 @@ Blockly.blockRendering.RenderInfo.prototype.addRowSpacing_ = function() { * @param {?Blockly.blockRendering.Row} prev The previous row, or null. * @param {?Blockly.blockRendering.Row} next The next row, or null. * @return {!Blockly.blockRendering.SpacerRow} The newly created spacer row. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.makeSpacerRow_ = function(prev, next) { var height = this.getSpacerRowHeight_(prev, next); @@ -593,7 +445,7 @@ Blockly.blockRendering.RenderInfo.prototype.makeSpacerRow_ = function(prev, next * @param {Blockly.blockRendering.Row} prev The row before the spacer. * @param {Blockly.blockRendering.Row} next The row after the spacer. * @return {number} The desired width of the spacer row between these two rows. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowWidth_ = function(prev, next) { // The width of the spacer before the bottom row should be the same as the @@ -609,29 +461,9 @@ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowWidth_ = function(prev, * @param {Blockly.blockRendering.Row} prev The row before the spacer. * @param {Blockly.blockRendering.Row} next The row after the spacer. * @return {number} The desired height of the spacer row between these two rows. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { - // If we have an empty block add a spacer to increase the height. - if (prev.type == 'top row' && next.type == 'bottom row') { - return Blockly.blockRendering.constants.EMPTY_BLOCK_SPACER_HEIGHT; - } - // Top and bottom rows act as a spacer so we don't need any extra padding. - if (prev.type == 'top row' || next.type == 'bottom row') { - return Blockly.blockRendering.constants.NO_PADDING; - } - if (prev.hasExternalInput && next.hasExternalInput) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - if (!prev.hasStatement && next.hasStatement) { - return Blockly.blockRendering.constants.BETWEEN_STATEMENT_PADDING_Y; - } - if (prev.hasStatement && next.hasStatement) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } - if (next.hasDummyInput) { - return Blockly.blockRendering.constants.LARGE_PADDING; - } return Blockly.blockRendering.constants.MEDIUM_PADDING; }; @@ -641,26 +473,16 @@ Blockly.blockRendering.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, * @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. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { - var result = row.yPos; - if (elem.isField() && row.hasStatement) { - var offset = Blockly.blockRendering.constants.TALL_INPUT_FIELD_OFFSET_Y + - elem.height / 2; - result += offset; - } else if (elem.isNextConnection()) { - result += (row.height - row.overhangY + elem.height / 2); - } else { - result += (row.height / 2); - } - return result; + return row.yPos + row.height / 2; }; /** * Make any final changes to the rendering information object. In particular, * store the y position of each row, and record the height of the full block. - * @private + * @protected */ Blockly.blockRendering.RenderInfo.prototype.finalize_ = function() { // Performance note: this could be combined with the draw pass, if the time @@ -675,15 +497,6 @@ Blockly.blockRendering.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; - if (row == this.bottomRow && - heightWithoutHat < Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT) { - // But the hat height shouldn't be part of this. - var diff = Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT - heightWithoutHat; - this.bottomRow.height += diff; - yCursor += diff; - } var xCursor = row.xPos; for (var j = 0, elem; (elem = row.elements[j]); j++) { elem.xPos = xCursor; diff --git a/core/renderers/block_rendering_rewrite/block_rendering.js b/core/renderers/block_rendering_rewrite/block_rendering.js index 2f0cd1b9d..f83f20151 100644 --- a/core/renderers/block_rendering_rewrite/block_rendering.js +++ b/core/renderers/block_rendering_rewrite/block_rendering.js @@ -34,6 +34,9 @@ goog.require('Blockly.blockRendering.Debug'); goog.require('Blockly.blockRendering.Drawer'); goog.require('Blockly.blockRendering.RenderInfo'); +goog.require('Blockly.geras.RenderInfo'); +goog.require('Blockly.thrasos.RenderInfo'); +goog.require('Blockly.zelos.RenderInfo'); /** * Render the given block, using the new rendering. @@ -45,6 +48,6 @@ Blockly.blockRendering.render = function(block) { if (!block.renderingDebugger) { block.renderingDebugger = new Blockly.blockRendering.Debug(); } - var info = new Blockly.blockRendering.RenderInfo(block); + var info = new Blockly.geras.RenderInfo(block); new Blockly.blockRendering.Drawer(block, info).draw_(); }; diff --git a/core/renderers/geras/info.js b/core/renderers/geras/info.js new file mode 100644 index 000000000..85955984f --- /dev/null +++ b/core/renderers/geras/info.js @@ -0,0 +1,382 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Old (compatibility) renderer. + * Geras: spirit of old age. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.geras'); +goog.provide('Blockly.geras.RenderInfo'); + +goog.require('Blockly.blockRendering.RenderInfo'); +goog.require('Blockly.blockRendering.constants'); +goog.require('Blockly.blockRendering.Measurable'); +goog.require('Blockly.blockRendering.BottomRow'); +goog.require('Blockly.blockRendering.InputRow'); +goog.require('Blockly.blockRendering.Row'); +goog.require('Blockly.blockRendering.SpacerRow'); +goog.require('Blockly.blockRendering.TopRow'); + +goog.require('Blockly.blockRendering.InlineInput'); +goog.require('Blockly.blockRendering.ExternalValueInput'); +goog.require('Blockly.blockRendering.StatementInput'); + +goog.require('Blockly.blockRendering.PreviousConnection'); +goog.require('Blockly.blockRendering.NextConnection'); +goog.require('Blockly.blockRendering.OutputConnection'); + +goog.require('Blockly.RenderedConnection'); + +/** + * An object containing all sizing information needed to draw this block. + * + * This measure pass does not propagate changes to the block (although fields + * may choose to rerender when getSize() is called). However, calling it + * repeatedly may be expensive. + * + * @param {!Blockly.BlockSvg} block The block to measure. + * @constructor + * @package + * @extends {Blockly.blockRendering.RenderInfo} + */ +Blockly.geras.RenderInfo = function(block) { + Blockly.geras.RenderInfo.superClass_.constructor.call(this, block); +}; +goog.inherits(Blockly.geras.RenderInfo, Blockly.blockRendering.RenderInfo); + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) { + // If this is the first input, just add to the existing row. + // That row is either empty or has some icons in it. + if (!lastInput) { + return false; + } + // A statement input always gets a new row. + if (input.type == Blockly.NEXT_STATEMENT) { + return true; + } + // Value and dummy inputs get new row if inputs are not inlined. + if (input.type == Blockly.INPUT_VALUE || input.type == Blockly.DUMMY_INPUT) { + return !this.isInline; + } + return false; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { + if (!prev) { + // Between an editable field and the beginning of the row. + if (next.isField() && next.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } + // Inline input at the beginning of the row. + if (next.isInput && next.isInlineInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } + if (next.isStatementInput()) { + return Blockly.blockRendering.constants.STATEMENT_INPUT_PADDING_LEFT; + } + // Anything else at the beginning of the row. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between a non-input and the end of the row. + if (!prev.isInput && !next) { + // Between an editable field and the end of the row. + if (prev.isField() && prev.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } + // Padding at the end of an icon-only row to make the block shape clearer. + if (prev.isIcon()) { + return (Blockly.blockRendering.constants.LARGE_PADDING * 2) + 1; + } + if (prev.isHat()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Establish a minimum width for a block with a previous or next connection. + if (prev.isPreviousConnection() || prev.isNextConnection()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + // Between rounded corner and the end of the row. + if (prev.isRoundedCorner()) { + return Blockly.blockRendering.constants.MIN_BLOCK_WIDTH; + } + // Between a jagged edge and the end of the row. + if (prev.isJaggedEdge()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Between noneditable fields and icons and the end of the row. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Between inputs and the end of the row. + if (prev.isInput && !next) { + if (prev.isExternalInput()) { + return Blockly.blockRendering.constants.NO_PADDING; + } else if (prev.isInlineInput()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } else if (prev.isStatementInput()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + } + + // Spacing between a non-input and an input. + if (!prev.isInput && next.isInput) { + // Between an editable field and an input. + if (prev.isEditable) { + if (next.isInlineInput()) { + return Blockly.blockRendering.constants.SMALL_PADDING; + } else if (next.isExternalInput()) { + return Blockly.blockRendering.constants.SMALL_PADDING; + } + } else { + if (next.isInlineInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } else if (next.isExternalInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } else if (next.isStatementInput()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + } + return Blockly.blockRendering.constants.LARGE_PADDING - 1; + } + + // Spacing between an icon and an icon or field. + if (prev.isIcon() && !next.isInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between an inline input and a field. + if (prev.isInlineInput() && !next.isInput) { + // Editable field after inline input. + if (next.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } else { + // Noneditable field after inline input. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + } + + if (prev.isSquareCorner()) { + // Spacing between a hat and a corner + if (next.isHat()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Spacing between a square corner and a previous or next connection + if (next.isPreviousConnection()) { + return next.notchOffset; + } else if (next.isNextConnection()) { + // Next connections are shifted slightly to the left (in both LTR and RTL) + // to make the dark path under the previous connection show through. + var offset = (this.RTL ? 1 : -1) * + Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; + return next.notchOffset + offset; + } + } + + // Spacing between a rounded corner and a previous or next connection. + if (prev.isRoundedCorner()) { + if (next.isPreviousConnection()) { + return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS; + } else if (next.isNextConnection()) { + // Next connections are shifted slightly to the left (in both LTR and RTL) + // to make the dark path under the previous connection show through. + var offset = (this.RTL ? 1 : -1) * + Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; + return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS + offset; + } + } + + // Spacing between two fields of the same editability. + if (!prev.isInput && !next.isInput && (prev.isEditable == next.isEditable)) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between anything and a jagged edge. + if (next.isJaggedEdge()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + return Blockly.blockRendering.constants.MEDIUM_PADDING; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.alignRowElements_ = function() { + for (var i = 0, row; (row = this.rows[i]); i++) { + if (!row.hasInlineInput) { + if (row.hasStatement) { + var statementInput = row.getLastInput(); + var currentWidth = row.width - statementInput.width; + var desiredWidth = this.statementEdge - this.startX; + } else { + var currentWidth = row.width; + var desiredWidth = this.width - this.startX; + } + if (row.type == 'bottom row' && row.hasFixedWidth) { + desiredWidth = Blockly.blockRendering.constants.MAX_BOTTOM_WIDTH; + } + var missingSpace = desiredWidth - currentWidth; + if (missingSpace) { + this.addAlignmentPadding_(row, missingSpace); + } + } + } +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) { + var elems = row.elements; + var input = row.getLastInput(); + if (input) { + var firstSpacer = row.getFirstSpacer(); + var lastSpacer = row.getLastSpacer(); + if (row.hasExternalInput || row.hasStatement) { + // Get the spacer right before the input socket. + lastSpacer = elems[elems.length - 3]; + row.widthWithConnectedBlocks += missingSpace; + } + // Decide where the extra padding goes. + if (input.align == Blockly.ALIGN_LEFT) { + // Add padding to the end of the row. + lastSpacer.width += missingSpace; + } else if (input.align == Blockly.ALIGN_CENTRE) { + // Split the padding between the beginning and end of the row. + firstSpacer.width += missingSpace / 2; + lastSpacer.width += missingSpace / 2; + } else if (input.align == Blockly.ALIGN_RIGHT) { + // Add padding at the beginning of the row. + firstSpacer.width += missingSpace; + } + row.width += missingSpace; + // Top and bottom rows are always left aligned. + } else if (row.type == 'top row' || row.type == 'bottom row') { + row.getLastSpacer().width += missingSpace; + row.width += missingSpace; + } +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.getSpacerRowWidth_ = function(prev, next) { + // The width of the spacer before the bottom row should be the same as the + // bottom row. + if (next.type == 'bottom row' && next.hasFixedWidth) { + return next.width; + } + return this.width - this.startX; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { + // If we have an empty block add a spacer to increase the height. + if (prev.type == 'top row' && next.type == 'bottom row') { + return Blockly.blockRendering.constants.EMPTY_BLOCK_SPACER_HEIGHT; + } + // Top and bottom rows act as a spacer so we don't need any extra padding. + if (prev.type == 'top row' || next.type == 'bottom row') { + return Blockly.blockRendering.constants.NO_PADDING; + } + if (prev.hasExternalInput && next.hasExternalInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + if (!prev.hasStatement && next.hasStatement) { + return Blockly.blockRendering.constants.BETWEEN_STATEMENT_PADDING_Y; + } + if (prev.hasStatement && next.hasStatement) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + if (next.hasDummyInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + return Blockly.blockRendering.constants.MEDIUM_PADDING; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { + var result = row.yPos; + if (elem.isField()) { + result += (elem.height / 2); + if (row.hasInlineInput || row.hasStatement) { + result += Blockly.blockRendering.constants.TALL_INPUT_FIELD_OFFSET_Y; + } + } else if (elem.isInlineInput()) { + result += elem.height / 2; + } else if (elem.isNextConnection()) { + result += (row.height - row.overhangY + elem.height / 2); + } else { + result += (row.height / 2); + } + return result; +}; + +/** + * @override + */ +Blockly.geras.RenderInfo.prototype.finalize_ = function() { + // Performance note: this could be combined with the draw pass, if the time + // that this takes is excessive. But it shouldn't be, because it only + // accesses and sets properties that already exist on the objects. + var widestRowWithConnectedBlocks = 0; + var yCursor = 0; + for (var i = 0, row; (row = this.rows[i]); i++) { + row.yPos = yCursor; + row.xPos = this.startX; + yCursor += row.height; + + widestRowWithConnectedBlocks = + Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); + // Add padding to the bottom row if block height is less than minimum + var heightWithoutHat = yCursor - this.topRow.startY; + if (row == this.bottomRow && + heightWithoutHat < Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT) { + // But the hat height shouldn't be part of this. + var diff = Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT - heightWithoutHat; + this.bottomRow.height += diff; + yCursor += diff; + } + var xCursor = row.xPos; + for (var j = 0, elem; (elem = row.elements[j]); j++) { + elem.xPos = xCursor; + elem.centerline = this.getElemCenterline_(row, elem); + xCursor += elem.width; + } + } + + this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; + + this.height = yCursor; + this.startY = this.topRow.startY; +}; diff --git a/core/renderers/measurables/rows.js b/core/renderers/measurables/rows.js index f39aed945..d7e9a4376 100644 --- a/core/renderers/measurables/rows.js +++ b/core/renderers/measurables/rows.js @@ -481,3 +481,12 @@ Blockly.blockRendering.InputRow.prototype.measure = function() { } this.widthWithConnectedBlocks = this.width + connectedBlockWidths; }; + + +Blockly.blockRendering.InputRow.prototype.getLastSpacer = function() { + if (this.hasExternalInput || this.hasStatement) { + var spacer = this.elements[this.elements.length - 3]; + return /** @type {Blockly.blockRendering.InRowSpacer} */ (spacer); + } + return Blockly.blockRendering.InputRow.superClass_.getLastSpacer.call(this); +}; diff --git a/core/renderers/thrasos/info.js b/core/renderers/thrasos/info.js new file mode 100644 index 000000000..2284a4286 --- /dev/null +++ b/core/renderers/thrasos/info.js @@ -0,0 +1,379 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview New (evolving) renderer. + * Thrasos: spirit of boldness. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.thrasos'); +goog.provide('Blockly.thrasos.RenderInfo'); + +goog.require('Blockly.blockRendering.RenderInfo'); +goog.require('Blockly.blockRendering.constants'); +goog.require('Blockly.blockRendering.Measurable'); +goog.require('Blockly.blockRendering.BottomRow'); +goog.require('Blockly.blockRendering.InputRow'); +goog.require('Blockly.blockRendering.Row'); +goog.require('Blockly.blockRendering.SpacerRow'); +goog.require('Blockly.blockRendering.TopRow'); + +goog.require('Blockly.blockRendering.InlineInput'); +goog.require('Blockly.blockRendering.ExternalValueInput'); +goog.require('Blockly.blockRendering.StatementInput'); + +goog.require('Blockly.blockRendering.PreviousConnection'); +goog.require('Blockly.blockRendering.NextConnection'); +goog.require('Blockly.blockRendering.OutputConnection'); + +goog.require('Blockly.RenderedConnection'); + +/** + * An object containing all sizing information needed to draw this block. + * + * This measure pass does not propagate changes to the block (although fields + * may choose to rerender when getSize() is called). However, calling it + * repeatedly may be expensive. + * + * @param {!Blockly.BlockSvg} block The block to measure. + * @constructor + * @package + * @extends {Blockly.blockRendering.RenderInfo} + */ +Blockly.thrasos.RenderInfo = function(block) { + Blockly.thrasos.RenderInfo.superClass_.constructor.call(this, block); +}; +goog.inherits(Blockly.thrasos.RenderInfo, Blockly.blockRendering.RenderInfo); + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) { + // If this is the first input, just add to the existing row. + // That row is either empty or has some icons in it. + if (!lastInput) { + return false; + } + // A statement input always gets a new row. + if (input.type == Blockly.NEXT_STATEMENT) { + return true; + } + // Value and dummy inputs get new row if inputs are not inlined. + if (input.type == Blockly.INPUT_VALUE || input.type == Blockly.DUMMY_INPUT) { + return !this.isInline; + } + return false; +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { + if (!prev) { + // Between an editable field and the beginning of the row. + if (next.isField() && next.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } + // Inline input at the beginning of the row. + if (next.isInput && next.isInlineInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } + if (next.isStatementInput()) { + return Blockly.blockRendering.constants.STATEMENT_INPUT_PADDING_LEFT; + } + // Anything else at the beginning of the row. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between a non-input and the end of the row. + if (!prev.isInput && !next) { + // Between an editable field and the end of the row. + if (prev.isField() && prev.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } + // Padding at the end of an icon-only row to make the block shape clearer. + if (prev.isIcon()) { + return (Blockly.blockRendering.constants.LARGE_PADDING * 2) + 1; + } + if (prev.isHat()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Establish a minimum width for a block with a previous or next connection. + if (prev.isPreviousConnection() || prev.isNextConnection()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + // Between rounded corner and the end of the row. + if (prev.isRoundedCorner()) { + return Blockly.blockRendering.constants.MIN_BLOCK_WIDTH; + } + // Between a jagged edge and the end of the row. + if (prev.isJaggedEdge()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Between noneditable fields and icons and the end of the row. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Between inputs and the end of the row. + if (prev.isInput && !next) { + if (prev.isExternalInput()) { + return Blockly.blockRendering.constants.NO_PADDING; + } else if (prev.isInlineInput()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } else if (prev.isStatementInput()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + } + + // Spacing between a non-input and an input. + if (!prev.isInput && next.isInput) { + // Between an editable field and an input. + if (prev.isEditable) { + if (next.isInlineInput()) { + return Blockly.blockRendering.constants.SMALL_PADDING; + } else if (next.isExternalInput()) { + return Blockly.blockRendering.constants.SMALL_PADDING; + } + } else { + if (next.isInlineInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } else if (next.isExternalInput()) { + return Blockly.blockRendering.constants.MEDIUM_LARGE_PADDING; + } else if (next.isStatementInput()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + } + return Blockly.blockRendering.constants.LARGE_PADDING - 1; + } + + // Spacing between an icon and an icon or field. + if (prev.isIcon() && !next.isInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between an inline input and a field. + if (prev.isInlineInput() && !next.isInput) { + // Editable field after inline input. + if (next.isEditable) { + return Blockly.blockRendering.constants.MEDIUM_PADDING; + } else { + // Noneditable field after inline input. + return Blockly.blockRendering.constants.LARGE_PADDING; + } + } + + if (prev.isSquareCorner()) { + // Spacing between a hat and a corner + if (next.isHat()) { + return Blockly.blockRendering.constants.NO_PADDING; + } + // Spacing between a square corner and a previous or next connection + if (next.isPreviousConnection()) { + return next.notchOffset; + } else if (next.isNextConnection()) { + // Next connections are shifted slightly to the left (in both LTR and RTL) + // to make the dark path under the previous connection show through. + var offset = (this.RTL ? 1 : -1) * + Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; + return next.notchOffset + offset; + } + } + + // Spacing between a rounded corner and a previous or next connection. + if (prev.isRoundedCorner()) { + if (next.isPreviousConnection()) { + return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS; + } else if (next.isNextConnection()) { + // Next connections are shifted slightly to the left (in both LTR and RTL) + // to make the dark path under the previous connection show through. + var offset = (this.RTL ? 1 : -1) * + Blockly.blockRendering.constants.DARK_PATH_OFFSET / 2; + return next.notchOffset - Blockly.blockRendering.constants.CORNER_RADIUS + offset; + } + } + + // Spacing between two fields of the same editability. + if (!prev.isInput && !next.isInput && (prev.isEditable == next.isEditable)) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + // Spacing between anything and a jagged edge. + if (next.isJaggedEdge()) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + + return Blockly.blockRendering.constants.MEDIUM_PADDING; +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.alignRowElements_ = function() { + for (var i = 0, row; (row = this.rows[i]); i++) { + if (!row.hasInlineInput) { + if (row.hasStatement) { + var statementInput = row.getLastInput(); + var currentWidth = row.width - statementInput.width; + var desiredWidth = this.statementEdge - this.startX; + } else { + var currentWidth = row.width; + var desiredWidth = this.width - this.startX; + } + if (row.type == 'bottom row' && row.hasFixedWidth) { + desiredWidth = Blockly.blockRendering.constants.MAX_BOTTOM_WIDTH; + } + var missingSpace = desiredWidth - currentWidth; + if (missingSpace) { + this.addAlignmentPadding_(row, missingSpace); + } + } + } +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) { + var elems = row.elements; + var input = row.getLastInput(); + if (input) { + var firstSpacer = row.getFirstSpacer(); + var lastSpacer = row.getLastSpacer(); + if (row.hasExternalInput || row.hasStatement) { + // Get the spacer right before the input socket. + lastSpacer = elems[elems.length - 3]; + row.widthWithConnectedBlocks += missingSpace; + } + // Decide where the extra padding goes. + if (input.align == Blockly.ALIGN_LEFT) { + // Add padding to the end of the row. + lastSpacer.width += missingSpace; + } else if (input.align == Blockly.ALIGN_CENTRE) { + // Split the padding between the beginning and end of the row. + firstSpacer.width += missingSpace / 2; + lastSpacer.width += missingSpace / 2; + } else if (input.align == Blockly.ALIGN_RIGHT) { + // Add padding at the beginning of the row. + firstSpacer.width += missingSpace; + } + row.width += missingSpace; + // Top and bottom rows are always left aligned. + } else if (row.type == 'top row' || row.type == 'bottom row') { + row.getLastSpacer().width += missingSpace; + row.width += missingSpace; + } +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.getSpacerRowWidth_ = function(prev, next) { + // The width of the spacer before the bottom row should be the same as the + // bottom row. + if (next.type == 'bottom row' && next.hasFixedWidth) { + return next.width; + } + return this.width - this.startX; +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) { + // If we have an empty block add a spacer to increase the height. + if (prev.type == 'top row' && next.type == 'bottom row') { + return Blockly.blockRendering.constants.EMPTY_BLOCK_SPACER_HEIGHT; + } + // Top and bottom rows act as a spacer so we don't need any extra padding. + if (prev.type == 'top row' || next.type == 'bottom row') { + return Blockly.blockRendering.constants.NO_PADDING; + } + if (prev.hasExternalInput && next.hasExternalInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + if (!prev.hasStatement && next.hasStatement) { + return Blockly.blockRendering.constants.BETWEEN_STATEMENT_PADDING_Y; + } + if (prev.hasStatement && next.hasStatement) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + if (next.hasDummyInput) { + return Blockly.blockRendering.constants.LARGE_PADDING; + } + return Blockly.blockRendering.constants.MEDIUM_PADDING; +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.getElemCenterline_ = function(row, elem) { + var result = row.yPos; + if (elem.isField() && row.hasStatement) { + var offset = Blockly.blockRendering.constants.TALL_INPUT_FIELD_OFFSET_Y + + elem.height / 2; + result += offset; + } else if (elem.isNextConnection()) { + result += (row.height - row.overhangY + elem.height / 2); + } else { + result += (row.height / 2); + } + return result; +}; + +/** + * @override + */ +Blockly.thrasos.RenderInfo.prototype.finalize_ = function() { + // Performance note: this could be combined with the draw pass, if the time + // that this takes is excessive. But it shouldn't be, because it only + // accesses and sets properties that already exist on the objects. + var widestRowWithConnectedBlocks = 0; + var yCursor = 0; + for (var i = 0, row; (row = this.rows[i]); i++) { + row.yPos = yCursor; + row.xPos = this.startX; + yCursor += row.height; + + widestRowWithConnectedBlocks = + Math.max(widestRowWithConnectedBlocks, row.widthWithConnectedBlocks); + // Add padding to the bottom row if block height is less than minimum + var heightWithoutHat = yCursor - this.topRow.startY; + if (row == this.bottomRow && + heightWithoutHat < Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT) { + // But the hat height shouldn't be part of this. + var diff = Blockly.blockRendering.constants.MIN_BLOCK_HEIGHT - heightWithoutHat; + this.bottomRow.height += diff; + yCursor += diff; + } + var xCursor = row.xPos; + for (var j = 0, elem; (elem = row.elements[j]); j++) { + elem.xPos = xCursor; + elem.centerline = this.getElemCenterline_(row, elem); + xCursor += elem.width; + } + } + + this.widthWithChildren = widestRowWithConnectedBlocks + this.startX; + + this.height = yCursor; + this.startY = this.topRow.startY; +}; diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js new file mode 100644 index 000000000..b4ab617f2 --- /dev/null +++ b/core/renderers/zelos/info.js @@ -0,0 +1,65 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Makecode/scratch-style renderer. + * Zelos: spirit of eager rivalry, emulation, envy, jealousy, and zeal. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.zelos'); +goog.provide('Blockly.zelos.RenderInfo'); + +goog.require('Blockly.blockRendering.RenderInfo'); +goog.require('Blockly.blockRendering.constants'); +goog.require('Blockly.blockRendering.Measurable'); +goog.require('Blockly.blockRendering.BottomRow'); +goog.require('Blockly.blockRendering.InputRow'); +goog.require('Blockly.blockRendering.Row'); +goog.require('Blockly.blockRendering.SpacerRow'); +goog.require('Blockly.blockRendering.TopRow'); + +goog.require('Blockly.blockRendering.InlineInput'); +goog.require('Blockly.blockRendering.ExternalValueInput'); +goog.require('Blockly.blockRendering.StatementInput'); + +goog.require('Blockly.blockRendering.PreviousConnection'); +goog.require('Blockly.blockRendering.NextConnection'); +goog.require('Blockly.blockRendering.OutputConnection'); + +goog.require('Blockly.RenderedConnection'); + +/** + * An object containing all sizing information needed to draw this block. + * + * This measure pass does not propagate changes to the block (although fields + * may choose to rerender when getSize() is called). However, calling it + * repeatedly may be expensive. + * + * @param {!Blockly.BlockSvg} block The block to measure. + * @constructor + * @package + * @extends {Blockly.blockRendering.RenderInfo} + */ +Blockly.zelos.RenderInfo = function(block) { + Blockly.zelos.RenderInfo.superClass_.constructor.call(this, block); +}; +goog.inherits(Blockly.zelos.RenderInfo, Blockly.blockRendering.RenderInfo);