From f9dcb60f82ebc79a5fc60c35e79d4ad4eb2002ee Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Wed, 13 Nov 2019 17:14:28 -0800 Subject: [PATCH] Zelos replacement highlight (#3431) * Zelos replacement highlight --- core/block_svg.js | 11 +++++ core/css.js | 11 +++-- core/inject.js | 4 +- core/insertion_marker_manager.js | 8 +++- core/renderers/common/path_object.js | 7 --- core/renderers/common/renderer.js | 13 +++++ core/renderers/zelos/constants.js | 71 ++++++++++++++++++++++++++-- core/renderers/zelos/path_object.js | 14 ++++++ core/renderers/zelos/renderer.js | 7 +++ 9 files changed, 129 insertions(+), 17 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index ce1b2e47d..a30725695 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1728,3 +1728,14 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { this.pathObject.updateReplacementHighlight(add); }; + +/** + * Determine whether or not to highlight a connection. + * @param {Blockly.Connection} conn The connection on the input to determine + * whether or not to highlight. + * @return {boolean} Whether or not to highlight the connection. + * @package + */ +Blockly.BlockSvg.prototype.shouldHighlightConnection = function(conn) { + return this.workspace.getRenderer().shouldHighlightConnection(conn); +}; diff --git a/core/css.js b/core/css.js index 110d4bd5d..568adc530 100644 --- a/core/css.js +++ b/core/css.js @@ -254,6 +254,11 @@ Blockly.Css.CONTENT = [ 'stroke-width: 1;', '}', + '.injectionDiv:not(.zelos-renderer) .blocklySelected>.blocklyPath {', + 'stroke: #fc3;', + 'stroke-width: 3px;', + '}', + '.blocklySelected>.blocklyPathLight {', 'display: none;', '}', @@ -320,12 +325,12 @@ Blockly.Css.CONTENT = [ 'stroke: none', '}', - '.blocklyReplaceable .blocklyPath {', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPath {', 'fill-opacity: .5;', '}', - '.blocklyReplaceable .blocklyPathLight,', - '.blocklyReplaceable .blocklyPathDark {', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPathLight,', + '.injectionDiv:not(.zelos-renderer) .blocklyReplaceable .blocklyPathDark {', 'display: none;', '}', diff --git a/core/inject.js b/core/inject.js index b7c8d3518..f284dd571 100644 --- a/core/inject.js +++ b/core/inject.js @@ -164,7 +164,9 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, mainWorkspace.scale = options.zoomOptions.startScale; svg.appendChild(mainWorkspace.createDom('blocklyMainBackground')); - // Set the theme name on the injection div. + // Set the theme name and renderer name onto the injection div. + Blockly.utils.dom.addClass(mainWorkspace.getInjectionDiv(), + (mainWorkspace.options.renderer || 'geras') + '-renderer'); Blockly.utils.dom.addClass(mainWorkspace.getInjectionDiv(), mainWorkspace.getTheme().name + '-theme'); diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 2be5213a0..7c711991f 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -504,7 +504,9 @@ Blockly.InsertionMarkerManager.prototype.showPreview_ = function() { this.connectMarker_(); } // Also highlight the actual connection, as a nod to previous behaviour. - if (this.closestConnection_) { + if (this.closestConnection_ && this.closestConnection_.targetBlock() && + this.closestConnection_.targetBlock() + .shouldHighlightConnection(this.closestConnection_)) { this.closestConnection_.highlight(); } }; @@ -548,7 +550,9 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) * @private */ Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { - if (this.closestConnection_) { + if (this.closestConnection_ && this.closestConnection_.targetBlock() && + this.closestConnection_.targetBlock() + .shouldHighlightConnection(this.closestConnection_)) { this.closestConnection_.unhighlight(); } if (this.highlightingBlock_) { diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 7b6fbe48f..7dd517de3 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -220,13 +220,6 @@ Blockly.blockRendering.PathObject.prototype.updateDisabled = function(disabled, */ Blockly.blockRendering.PathObject.prototype.updateSelected = function(enable) { this.setClass_('blocklySelected', enable); - if (enable) { - this.svgPath.setAttribute('stroke', '#fc3'); - this.svgPath.setAttribute('stroke-width', '3px'); - } else { - this.svgPath.setAttribute('stroke', ''); - this.svgPath.setAttribute('stroke-width', ''); - } }; /** diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js index c6f16677c..a25e52825 100644 --- a/core/renderers/common/renderer.js +++ b/core/renderers/common/renderer.js @@ -139,6 +139,19 @@ Blockly.blockRendering.Renderer.prototype.getConstants = function() { (this.constants_)); }; +/** + * Determine whether or not to highlight a connection. + * @param {Blockly.Connection} _conn The connection to determine whether or not + * to highlight. + * @return {boolean} True if we should highlight the connection. + * @package + */ +Blockly.blockRendering.Renderer.prototype.shouldHighlightConnection = + function(_conn) { + /* eslint-disable indent */ + return true; +}; /* eslint-enable indent */ + /** * Render the block. * @param {!Blockly.BlockSvg} block The block to render. diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 90f888969..f982a6307 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -127,6 +127,11 @@ Blockly.zelos.ConstantProvider = function() { */ this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT; + /** + * @override + */ + this.FULL_BLOCK_FIELDS = true; + /** * @override */ @@ -158,9 +163,19 @@ Blockly.zelos.ConstantProvider = function() { this.highlightGlowFilter_ = null; /** - * @override + * The ID of the highlight glow filter, or the empty string if no filter is + * set. + * @type {string} + * @package */ - this.FULL_BLOCK_FIELDS = true; + this.replacementGlowFilterId = ''; + + /** + * The element to use for a higlight glow, or null if not set. + * @type {SVGElement} + * @private + */ + this.replacementGlowFilter_ = null; }; Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider, Blockly.blockRendering.ConstantProvider); @@ -424,13 +439,13 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) { }, highlightGlowFilter); // Set all gaussian blur pixels to 1 opacity before applying flood - var componentTransfer = Blockly.utils.dom.createSvgElement( + var highlightComponentTransfer = Blockly.utils.dom.createSvgElement( 'feComponentTransfer', {'result': 'outBlur'}, highlightGlowFilter); Blockly.utils.dom.createSvgElement('feFuncA', { 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' }, - componentTransfer); + highlightComponentTransfer); // Color the highlight Blockly.utils.dom.createSvgElement('feFlood', { @@ -447,4 +462,52 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg) { highlightGlowFilter); this.highlightGlowFilterId = highlightGlowFilter.id; this.highlightGlowFilter_ = highlightGlowFilter; + + // Using a dilate distorts the block shape. + // Instead use a gaussian blur, and then set all alpha to 1 with a transfer. + var replacementGlowFilter = Blockly.utils.dom.createSvgElement('filter', + { + 'id': 'blocklyReplacementGlowFilter' + rnd, + 'height': '160%', + 'width': '180%', + y: '-30%', + x: '-40%' + }, + defs); + Blockly.utils.dom.createSvgElement('feGaussianBlur', + { + 'in': 'SourceGraphic', + 'stdDeviation': 2 // TODO: configure size in theme. + }, + replacementGlowFilter); + // Set all gaussian blur pixels to 1 opacity before applying flood + var replacementComponentTransfer = Blockly.utils.dom.createSvgElement( + 'feComponentTransfer', {'result': 'outBlur'}, replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feFuncA', + { + 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' + }, + replacementComponentTransfer); + // Color the highlight + Blockly.utils.dom.createSvgElement('feFlood', + { + 'flood-color': '#FFF200', // TODO: configure colour in theme. + 'flood-opacity': 1, + 'result': 'outColor' + }, + replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'outColor', 'in2': 'outBlur', + 'operator': 'in', 'result': 'outGlow' + }, + replacementGlowFilter); + Blockly.utils.dom.createSvgElement('feComposite', + { + 'in': 'SourceGraphic', 'in2': 'outGlow', + 'operator': 'over', + }, + replacementGlowFilter); + this.replacementGlowFilterId = replacementGlowFilter.id; + this.replacementGlowFilter_ = replacementGlowFilter; }; diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index e840c4efa..bb4240a34 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -117,6 +117,20 @@ Blockly.zelos.PathObject.prototype.updateSelected = function(enable) { } }; +/** + * @override + */ +Blockly.zelos.PathObject.prototype.updateReplacementHighlight = function( + enable) { + this.setClass_('blocklyReplaceable', enable); + if (enable) { + this.svgPath.setAttribute('filter', + 'url(#' + this.constants_.replacementGlowFilterId + ')'); + } else { + this.svgPath.removeAttribute('filter'); + } +}; + /** * Method that's called when the drawer is about to draw the block. * @package diff --git a/core/renderers/zelos/renderer.js b/core/renderers/zelos/renderer.js index a075e2f13..47d4134da 100644 --- a/core/renderers/zelos/renderer.js +++ b/core/renderers/zelos/renderer.js @@ -91,4 +91,11 @@ Blockly.zelos.Renderer.prototype.makePathObject = function(root) { /** @type {!Blockly.zelos.ConstantProvider} */ (this.getConstants())); }; +/** + * @override + */ +Blockly.zelos.Renderer.prototype.shouldHighlightConnection = function(conn) { + return conn.type != Blockly.INPUT_VALUE && conn.type !== Blockly.OUTPUT_VALUE; +}; + Blockly.blockRendering.register('zelos', Blockly.zelos.Renderer);