From dc1e7b82fe59691b2607f4f2a83268b22995bd66 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 26 Aug 2019 17:49:42 -0700 Subject: [PATCH] Zelos notch (#2918) * Add the zelos notch --- blockly_uncompressed.js | 4 +- core/renderers/common/block_rendering.js | 5 +- core/renderers/zelos/constants.js | 65 +++++++++++ core/renderers/zelos/drawer.js | 47 ++++++++ core/renderers/zelos/info.js | 141 +++++++++++++++++++++++ 5 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 core/renderers/zelos/drawer.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 0e6eba333..b6e7563c2 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -92,7 +92,7 @@ goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []); goog.addDependency("../../../" + dir + "/core/options.js", ['Blockly.Options'], ['Blockly.Themes.Classic', 'Blockly.utils.userAgent', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); -goog.addDependency("../../../" + dir + "/core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.ConstantProvider', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.RenderInfo', 'Blockly.geras.Drawer', 'Blockly.thrasos.RenderInfo', 'Blockly.zelos.RenderInfo', 'Blockly.zelos.ConstantProvider']); +goog.addDependency("../../../" + dir + "/core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.ConstantProvider', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.RenderInfo', 'Blockly.thrasos.RenderInfo', 'Blockly.zelos.Drawer', 'Blockly.zelos.RenderInfo', 'Blockly.zelos.ConstantProvider']); goog.addDependency("../../../" + dir + "/core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.svgPaths']); goog.addDependency("../../../" + dir + "/core/renderers/common/debugger.js", ['Blockly.blockRendering.Debug'], ['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/common/drawer.js", ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.Debug', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow']); @@ -108,6 +108,7 @@ goog.addDependency("../../../" + dir + "/core/renderers/measurables/row_elements 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.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.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/constants.js", ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.svgPaths']); +goog.addDependency("../../../" + dir + "/core/renderers/zelos/drawer.js", ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.zelos.RenderInfo']); goog.addDependency("../../../" + dir + "/core/renderers/zelos/info.js", ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.RenderInfo', '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'], []); @@ -322,6 +323,7 @@ goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils.xml'); goog.require('Blockly.zelos'); goog.require('Blockly.zelos.ConstantProvider'); +goog.require('Blockly.zelos.Drawer'); goog.require('Blockly.zelos.RenderInfo'); delete root.BLOCKLY_DIR; diff --git a/core/renderers/common/block_rendering.js b/core/renderers/common/block_rendering.js index 41ae85a42..568c717be 100644 --- a/core/renderers/common/block_rendering.js +++ b/core/renderers/common/block_rendering.js @@ -36,9 +36,10 @@ goog.require('Blockly.blockRendering.RenderInfo'); goog.require('Blockly.blockRendering.ConstantProvider'); goog.require('Blockly.geras.HighlightConstantProvider'); -goog.require('Blockly.geras.RenderInfo'); goog.require('Blockly.geras.Drawer'); +goog.require('Blockly.geras.RenderInfo'); goog.require('Blockly.thrasos.RenderInfo'); +goog.require('Blockly.zelos.Drawer'); goog.require('Blockly.zelos.RenderInfo'); goog.require('Blockly.zelos.ConstantProvider'); @@ -86,7 +87,7 @@ Blockly.blockRendering.render = function(block) { new Blockly.blockRendering.Drawer(block, info).draw(); } else if (Blockly.blockRendering.rendererName == 'zelos') { var info = new Blockly.zelos.RenderInfo(block); - new Blockly.blockRendering.Drawer(block, info).draw(); + new Blockly.zelos.Drawer(block, info).draw(); } }; diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 7c86d1cf0..0dd93adce 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -38,6 +38,14 @@ goog.require('Blockly.utils.svgPaths'); */ Blockly.zelos.ConstantProvider = function() { Blockly.zelos.ConstantProvider.superClass_.constructor.call(this); + + this.CORNER_RADIUS = 4; + + this.NOTCH_WIDTH = 36; + + this.NOTCH_HEIGHT = 8; + + this.NOTCH_OFFSET_LEFT = 12; }; goog.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); @@ -100,3 +108,60 @@ Blockly.zelos.ConstantProvider.prototype.shapeFor = function( throw new Error('Unknown type'); } }; + +/** + * @override + */ +Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() { + var width = this.NOTCH_WIDTH; + var height = this.NOTCH_HEIGHT; + + var innerWidth = width / 3; + var curveWidth = innerWidth / 3; + + var halfHeight = height / 2; + var quarterHeight = halfHeight / 2; + + function makeMainPath(dir) { + return ( + Blockly.utils.svgPaths.curve('c', [ + Blockly.utils.svgPaths.point(dir * curveWidth / 2, 0), + Blockly.utils.svgPaths.point(dir * curveWidth * 3 / 4, quarterHeight / 2), + Blockly.utils.svgPaths.point(dir * curveWidth, quarterHeight) + ]) + + Blockly.utils.svgPaths.line([ + Blockly.utils.svgPaths.point(dir * curveWidth, halfHeight) + ]) + + Blockly.utils.svgPaths.curve('c', [ + Blockly.utils.svgPaths.point(dir * curveWidth / 4, quarterHeight / 2), + Blockly.utils.svgPaths.point(dir * curveWidth / 2, quarterHeight), + Blockly.utils.svgPaths.point(dir * curveWidth, quarterHeight) + ]) + + Blockly.utils.svgPaths.lineOnAxis('h', dir * innerWidth) + + Blockly.utils.svgPaths.curve('c', [ + Blockly.utils.svgPaths.point(dir * curveWidth / 2, 0), + Blockly.utils.svgPaths.point(dir * curveWidth * 3 / 4, -(quarterHeight / 2)), + Blockly.utils.svgPaths.point(dir * curveWidth, -quarterHeight) + ]) + + Blockly.utils.svgPaths.line([ + Blockly.utils.svgPaths.point(dir * curveWidth, -halfHeight) + ]) + + Blockly.utils.svgPaths.curve('c', [ + Blockly.utils.svgPaths.point(dir * curveWidth / 4, -(quarterHeight / 2)), + Blockly.utils.svgPaths.point(dir * curveWidth / 2, -quarterHeight), + Blockly.utils.svgPaths.point(dir * curveWidth, -quarterHeight) + ]) + ); + } + + // TODO: Find a relationship between width and path + var pathLeft = makeMainPath(1); + var pathRight = makeMainPath(-1); + + return { + width: width, + height: height, + pathLeft: pathLeft, + pathRight: pathRight + }; +}; diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js new file mode 100644 index 000000000..7bfe4e4ac --- /dev/null +++ b/core/renderers/zelos/drawer.js @@ -0,0 +1,47 @@ +/** + * @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 Zelos renderer. + * @author samelh@google.com (Sam El-Husseini) + */ +'use strict'; + +goog.provide('Blockly.zelos.Drawer'); + +goog.require('Blockly.blockRendering.ConstantProvider'); +goog.require('Blockly.blockRendering.Drawer'); +goog.require('Blockly.zelos.RenderInfo'); + + +/** + * An object that draws a block based on the given rendering information. + * @param {!Blockly.BlockSvg} block The block to render. + * @param {!Blockly.zelos.RenderInfo} info An object containing all + * information needed to render this block. + * @package + * @constructor + * @extends {Blockly.blockRendering.Drawer} + */ +Blockly.zelos.Drawer = function(block, info) { + Blockly.zelos.Drawer.superClass_.constructor.call(this, block, info); +}; +goog.inherits(Blockly.zelos.Drawer, Blockly.blockRendering.Drawer); + diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index 4664f0239..0e0af2d90 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -62,3 +62,144 @@ Blockly.zelos.RenderInfo = function(block) { Blockly.zelos.RenderInfo.superClass_.constructor.call(this, block); }; goog.inherits(Blockly.zelos.RenderInfo, Blockly.blockRendering.RenderInfo); + + +/** + * @override + */ +Blockly.zelos.RenderInfo.prototype.getInRowSpacing_ = function(prev, next) { + if (!prev) { + // Between an editable field and the beginning of the row. + if (next.isField() && next.isEditable) { + return this.constants_.MEDIUM_PADDING; + } + // Inline input at the beginning of the row. + if (next.isInput && next.isInlineInput()) { + return this.constants_.MEDIUM_LARGE_PADDING; + } + if (next.isStatementInput()) { + return this.constants_.STATEMENT_INPUT_PADDING_LEFT; + } + // Anything else at the beginning of the row. + return this.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 this.constants_.MEDIUM_PADDING; + } + // Padding at the end of an icon-only row to make the block shape clearer. + if (prev.isIcon()) { + return (this.constants_.LARGE_PADDING * 2) + 1; + } + if (prev.isHat()) { + return this.constants_.NO_PADDING; + } + // Establish a minimum width for a block with a previous or next connection. + if (prev.isPreviousConnection() || prev.isNextConnection()) { + return this.constants_.LARGE_PADDING; + } + // Between rounded corner and the end of the row. + if (prev.isRoundedCorner()) { + return this.constants_.MIN_BLOCK_WIDTH; + } + // Between a jagged edge and the end of the row. + if (prev.isJaggedEdge()) { + return this.constants_.NO_PADDING; + } + // Between noneditable fields and icons and the end of the row. + return this.constants_.LARGE_PADDING; + } + + // Between inputs and the end of the row. + if (prev.isInput && !next) { + if (prev.isExternalInput()) { + return this.constants_.NO_PADDING; + } else if (prev.isInlineInput()) { + return this.constants_.LARGE_PADDING; + } else if (prev.isStatementInput()) { + return this.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 this.constants_.SMALL_PADDING; + } else if (next.isExternalInput()) { + return this.constants_.SMALL_PADDING; + } + } else { + if (next.isInlineInput()) { + return this.constants_.MEDIUM_LARGE_PADDING; + } else if (next.isExternalInput()) { + return this.constants_.MEDIUM_LARGE_PADDING; + } else if (next.isStatementInput()) { + return this.constants_.LARGE_PADDING; + } + } + return this.constants_.LARGE_PADDING - 1; + } + + // Spacing between an icon and an icon or field. + if (prev.isIcon() && !next.isInput) { + return this.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 this.constants_.MEDIUM_PADDING; + } else { + // Noneditable field after inline input. + return this.constants_.LARGE_PADDING; + } + } + + if (prev.isSquareCorner()) { + // Spacing between a hat and a corner + if (next.isHat()) { + return this.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) * + this.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 - this.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) * + this.constants_.DARK_PATH_OFFSET / 2; + return next.notchOffset - this.constants_.CORNER_RADIUS + offset; + } + } + + // Spacing between two fields of the same editability. + if (!prev.isInput && !next.isInput && (prev.isEditable == next.isEditable)) { + return this.constants_.LARGE_PADDING; + } + + // Spacing between anything and a jagged edge. + if (next.isJaggedEdge()) { + return this.constants_.LARGE_PADDING; + } + + return this.constants_.MEDIUM_PADDING; +};