Cleanup of colouring code, and move it into path_object.

This commit is contained in:
Rachel Fenichel
2019-10-28 14:57:36 -07:00
parent 85c4db5a10
commit 6f520335ea
14 changed files with 166 additions and 310 deletions

View File

@@ -934,9 +934,9 @@ Blockly.Block.prototype.setColour = function(colour) {
// Set colour just stores these as properties on the block, but never uses
// them again.
// TODO: see if we can just get rid of these properties on the block.
var parsed = Blockly.blockRendering.Colourer.parseColour(colour);
var parsed = Blockly.utils.colour.parseBlockColour(colour);
this.hue_ = parsed.hue;
this.colour_ = parsed.colour;
this.colour_ = parsed.hex;
};
/**

View File

@@ -68,25 +68,9 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
* @type {Blockly.blockRendering.IPathObject}
* @package
*/
this.pathObject =
workspace.getRenderer().makePathObject(this.svgGroup_);
/**
* [colourer description]
* @type {[type]}
* @package
*/
this.colourer =
workspace.getRenderer().makeColourer(this, this.pathObject);
// The next three paths are set only for backwards compatibility reasons.
/**
* The dark path of the block.
* @type {SVGElement}
* @private
*/
this.svgPathDark_ = this.pathObject.svgPathDark || null;
this.pathObject = workspace.getRenderer().makePathObject(this.svgGroup_);
// The next two paths are set only for backwards compatibility reasons.
/**
* The primary path of the block.
* @type {SVGElement}
@@ -1035,7 +1019,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) {
this.svgGroup_ = null;
this.svgPath_ = null;
this.svgPathLight_ = null;
this.svgPathDark_ = null;
Blockly.utils.dom.stopTextWidthCache();
};
@@ -1049,7 +1032,7 @@ Blockly.BlockSvg.prototype.applyColour = function() {
return;
}
this.colourer.applyColour(this.isShadow());
this.pathObject.applyColour(this.isShadow());
var icons = this.getIcons();
for (var i = 0; i < icons.length; i++) {
@@ -1314,7 +1297,7 @@ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) {
* @return {string} #RRGGBB string.
*/
Blockly.BlockSvg.prototype.getColour = function() {
return this.colourer.getColour();
return this.pathObject.primaryColour;
};
/**
@@ -1323,7 +1306,7 @@ Blockly.BlockSvg.prototype.getColour = function() {
*/
Blockly.BlockSvg.prototype.setColour = function(colour) {
Blockly.BlockSvg.superClass_.setColour.call(this, colour);
this.colourer.setColour(colour);
this.pathObject.setColour(colour);
this.applyColour();
};
@@ -1339,7 +1322,7 @@ Blockly.BlockSvg.prototype.setStyle = function(blockStyleName) {
if (blockStyle) {
this.hat = blockStyle.hat;
this.colourer.setFromStyle(blockStyle);
this.pathObject.setFromStyle(blockStyle);
this.applyColour();
} else {
throw Error('Invalid style name: ' + blockStyleName);

View File

@@ -269,9 +269,9 @@ Blockly.FieldAngle.prototype.showEditor_ = function() {
var editor = this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(editor);
var colourer = this.sourceBlock_.colourer;
Blockly.DropDownDiv.setColour(colourer.getColour(),
colourer.getBorderColour());
var pathObject = this.sourceBlock_.pathObject;
Blockly.DropDownDiv.setColour(pathObject.primaryColour,
pathObject.tertiaryColour);
Blockly.DropDownDiv.showPositionedByField(
this, this.dropdownDispose_.bind(this));

View File

@@ -130,8 +130,8 @@ Blockly.FieldDate.prototype.render_ = function() {
* @package
*/
Blockly.FieldDate.prototype.applyColour = function() {
this.todayColour_ = this.sourceBlock_.colourer.getColour();
this.selectedColour_ = this.sourceBlock_.colourer.getShadowColour();
this.todayColour_ = this.sourceBlock_.pathObject.primaryColour;
this.selectedColour_ = this.sourceBlock_.pathObject.secondaryColour;
this.updateEditor_();
};

View File

@@ -472,9 +472,9 @@ Blockly.FieldDropdown.prototype.applyColour = function() {
// Update arrow's colour.
if (this.sourceBlock_ && this.arrow_) {
if (this.sourceBlock_.isShadow()) {
this.arrow_.style.fill = this.sourceBlock_.colourer.getColourShadow();
this.arrow_.style.fill = this.sourceBlock_.pathObject.secondaryColour;
} else {
this.arrow_.style.fill = this.sourceBlock_.colourer.getColour();
this.arrow_.style.fill = this.sourceBlock_.pathObject.primaryColour;
}
}
};

View File

@@ -141,7 +141,7 @@ Blockly.Icon.prototype.iconClick_ = function(e) {
*/
Blockly.Icon.prototype.applyColour = function() {
if (this.isVisible()) {
this.bubble_.setColour(this.block_.colourer.getColour());
this.bubble_.setColour(this.block_.pathObject.primaryColour);
}
};

View File

@@ -1,131 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
*
* 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
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.blockRendering.Colourer');
goog.provide('Blockly.blockRendering.IColourer');
goog.require('Blockly.blockRendering.IPathObject');
/**
* An interface for a block's colourer object.
* @param {!SVGElement} _root The root SVG element.
* @interface
*/
Blockly.blockRendering.IColourer = function(block, pathObject) {};
/**
* )
* @param {[type]} block [description]
* @param {[type]} pathObject [description]
* @implements {Blockly.blockRendering.IColourer}
* @constructor
*/
Blockly.blockRendering.Colourer = function(block, pathObject) {
this.block = block;
/**
* The renderer's path object.
* @type {Blockly.blockRendering.IPathObject}
* @package
*/
this.pathObject = /** {Blockly.BlockRender.PathObject} */ (pathObject);
this.svgPath = this.pathObject.svgPath;
this.hue_;
this.colour_;
this.colourSecondary_;
this.colourTertiary_;
};
Blockly.blockRendering.Colourer.prototype.applyColours = function(isShadow) {
if (isShadow) {
this.svgPath.setAttribute('stroke', 'none');
this.svgPath.setAttribute('fill', this.colourSecondary_);
} else {
this.svgPath.setAttribute('stroke', this.colourTertiary_);
this.svgPath.setAttribute('fill', this.colour_);
}
};
/**
* Change the colour of a block.
* @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string,
* or a message reference string pointing to one of those two values.
*/
Blockly.blockRendering.Colourer.prototype.setColour = function(colour) {
console.log('todo: set colour');
// this.colour_ = colour;
// this.colourSecondary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.6);
// this.colourTertiary_ = Blockly.utils.colour.blend('#fff', this.colour, 0.3);
};
Blockly.blockRendering.Colourer.prototype.setFromStyle = function(blockStyle) {
this.parseColour(blockStyle['colourPrimary']);
this.colourSecondary_ = blockStyle['colourSecondary'] ||
Blockly.utils.colour.blend('#fff', this.colour_, 0.6);
this.colourTertiary_ = blockStyle['colourTertiary'] ||
Blockly.utils.colour.blend('#fff', this.colour_, 0.3);
};
Blockly.blockRendering.Colourer.prototype.getBorderColour = function() {
return this.colourTertiary_;
};
Blockly.blockRendering.Colourer.prototype.getShadowColour = function() {
return this.colourSecondary_;
};
/**
* Change the colour of a block.
* @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string,
* or a message reference string pointing to one of those two values.
* @return {{hue: ?number, colour: string}} An object containing the colour as
* a #RRGGBB string, and the hue if the input was an HSV hue value.
*/
Blockly.blockRendering.Colourer.parseColour = function(colour) {
var dereferenced = (typeof colour == 'string') ?
Blockly.utils.replaceMessageReferences(colour) : colour;
var hue = Number(dereferenced);
if (!isNaN(hue) && 0 <= hue && hue <= 360) {
return {
hue: hue,
colour: Blockly.hueToHex(hue)
};
} else {
var hex = Blockly.utils.colour.parse(dereferenced);
if (hex) {
// Only store hue if colour is set as a hue.
return {
hue: null,
colour: hex
};
} else {
var errorMsg = 'Invalid colour: "' + dereferenced + '"';
if (colour != dereferenced) {
errorMsg += ' (from "' + colour + '")';
}
throw Error(errorMsg);
}
}
};

View File

@@ -74,6 +74,12 @@ Blockly.blockRendering.PathObject = function(root) {
this.svgPathDark = Blockly.utils.dom.createSvgElement('path',
{'class': 'blocklyPathDark', 'transform': 'translate(1,1)'},
this.svgRoot);
this.hue_;
this.primaryColour;
this.secondaryColour;
this.tertiaryColour;
};
/**
@@ -95,3 +101,67 @@ Blockly.blockRendering.PathObject.prototype.flipRTL = function() {
// Mirror the block's path.
this.svgPath.setAttribute('transform', 'scale(-1 1)');
};
/**
* Apply the stored colours to the block's path, taking into account whether
* the paths belong to a shadow block.
* @param {boolean} isShadow True if the block is a shadow block.
* @package
*/
Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) {
if (isShadow) {
this.svgPath.setAttribute('stroke', 'none');
this.svgPath.setAttribute('fill', this.secondaryColour);
} else {
this.svgPath.setAttribute('stroke', this.tertiaryColour);
this.svgPath.setAttribute('fill', this.primaryColour);
}
};
/**
* Update colour properties based on a triplet of colours.
* @param {string} primary The primary colour.
* @param {string} secondary The secondary colour, or null to have the colourer
* generate it.
* @param {string} tertiary The tertiary colour, or null to have the colourer
* generate it.
* @package
*/
Blockly.blockRendering.PathObject.prototype.setColourFromTriplet = function(
primary, secondary, tertiary) {
this.primaryColour = primary;
this.secondaryColour = secondary ||
Blockly.utils.colour.blend('#fff', primary, 0.6);
this.tertiaryColour = tertiary ||
Blockly.utils.colour.blend('#fff', primary, 0.3);
};
/**
* Update colour properties based on a single colour value.
* @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string,
* or a message reference string pointing to one of those two values.
*/
Blockly.blockRendering.PathObject.prototype.setColour = function(colour) {
var parsed = Blockly.utils.colour.parseBlockColour(colour);
if (parsed.hue) {
this.hue_ = parsed.hue;
}
this.setColourFromTriplet(parsed.hex, null, null);
};
/**
* Update colour properties based on a block style.
* @param {!Blockly.Theme.BlockStyle} blockStyle The block style to use.
* @package
*/
Blockly.blockRendering.PathObject.prototype.setFromStyle = function(
blockStyle) {
var parsed =
Blockly.utils.colour.parseBlockColour(blockStyle['colourPrimary']);
if (parsed.hue) {
this.hue_ = parsed.hue;
}
this.setColourFromTriplet(parsed.hex,
blockStyle['colourSecondary'],
blockStyle['colourTertiary']);
};

View File

@@ -28,8 +28,6 @@ goog.require('Blockly.blockRendering.Drawer');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.blockRendering.PathObject');
goog.require('Blockly.blockRendering.RenderInfo');
goog.require('Blockly.blockRendering.IColourer');
goog.require('Blockly.blockRendering.Colourer');
goog.require('Blockly.CursorSvg');
goog.requireType('Blockly.blockRendering.Debug');
@@ -127,18 +125,6 @@ Blockly.blockRendering.Renderer.prototype.makePathObject = function(root) {
return new Blockly.blockRendering.PathObject(root);
};
/**
* Create a new instance of a renderer path object.
* @param {!Blockly.BlockSvg} block The root SVG element.
* @param {!Blockly.blockRendering.IPathObject} pathObject [description]
* @return {!Blockly.blockRendering.IColourer} The renderer path object.
* @package
*/
Blockly.blockRendering.Renderer.prototype.makeColourer = function(block,
pathObject) {
return new Blockly.blockRendering.Colourer(block, pathObject);
};
/**
* Get the current renderer's constant provider. We assume that when this is
* called, the renderer has already been initialized.

View File

@@ -1,119 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
*
* 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
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.geras.Colourer');
goog.require('Blockly.geras.PathObject');
/**
* )
* @param {[type]} block [description]
* @param {[type]} pathObject [description]
* @implements {Blockly.blockRendering.IColourer}
* @constructor
*/
Blockly.geras.Colourer = function(block, pathObject) {
/**
* The renderer's path object.
* @type {Blockly.geras.PathObject}
* @package
*/
this.pathObject = /** {Blockly.geras.PathObject} */ (pathObject);
this.svgPath = this.pathObject.svgPath;
this.svgPathLight = this.pathObject.svgPathLight;
this.svgPathDark = this.pathObject.svgPathDark;
this.svgPath.setAttribute('stroke', 'none');
this.svgPathLight.style.display = '';
this.svgPathDark.setAttribute('display', '');
this.colour_;
this.colourTertiary_;
this.colourDark_;
this.colourSecondary_;
this.styleName_;
};
Blockly.geras.Colourer.prototype.applyColour = function(isShadow) {
if (isShadow) {
this.svgPathLight.style.display = 'none';
this.svgPathDark.setAttribute('fill', this.colourSecondary_);
this.svgPath.setAttribute('stroke', 'none');
this.svgPath.setAttribute('fill', this.colourSecondary_);
} else {
this.svgPathLight.style.display = '';
this.svgPathDark.style.display = '';
this.svgPath.setAttribute('stroke', 'none');
this.svgPathLight.setAttribute('stroke', this.colourTertiary_);
this.svgPathDark.setAttribute('fill', this.colourDark_);
this.svgPath.setAttribute('fill', this.colour_);
}
};
/**
* Get the colour of a block.
* @return {string} #RRGGBB string.
*/
Blockly.geras.Colourer.prototype.getColour = function() {
return this.colour_;
};
Blockly.geras.Colourer.prototype.getShadowColour = function() {
return this.colourSecondary_;
};
Blockly.geras.Colourer.prototype.getBorderColour = function() {
return this.colourTertiary_;
};
Blockly.geras.Colourer.prototype.setColourFromTriplet = function(primary,
secondary, tertiary) {
this.colour_ = primary;
this.colourSecondary_ = secondary ||
Blockly.utils.colour.blend('#fff', primary, 0.6);
this.colourTertiary_ = tertiary ||
Blockly.utils.colour.blend('#fff', primary, 0.3);
this.colourDark_ = tertiary ||
Blockly.utils.colour.blend('#000', primary, 0.2);
};
/**
* Change the colour of a block.
* @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string,
* or a message reference string pointing to one of those two values.
*/
Blockly.geras.Colourer.prototype.setColour = function(colour) {
var primary = Blockly.blockRendering.Colourer.parseColour(colour).colour;
this.setColourFromTriplet(primary, null, null);
};
Blockly.geras.Colourer.prototype.setFromStyle = function(blockStyle) {
var primary =
Blockly.blockRendering.Colourer.parseColour(blockStyle['colourPrimary'])
.colour;
this.setColourFromTriplet(primary,
blockStyle['colourSecondary'],
blockStyle['colourTertiary']);
};

View File

@@ -34,6 +34,7 @@ goog.require('Blockly.utils.dom');
* @param {!SVGElement} root The root SVG element.
* @constructor
* @implements {Blockly.blockRendering.IPathObject}
* @extends {Blockly.blockRendering.PathObject}
* @package
*/
Blockly.geras.PathObject = function(root) {
@@ -66,7 +67,16 @@ Blockly.geras.PathObject = function(root) {
*/
this.svgPathLight = Blockly.utils.dom.createSvgElement('path',
{'class': 'blocklyPathLight'}, this.svgRoot);
this.hue_;
this.primaryColour;
this.secondaryColour;
this.tertiaryColour;
this.darkColour;
};
Blockly.utils.object.inherits(Blockly.geras.PathObject,
Blockly.blockRendering.PathObject);
/**
* Set each of the paths generated by the renderer onto the respective SVG element.
@@ -90,3 +100,36 @@ Blockly.geras.PathObject.prototype.flipRTL = function() {
this.svgPathLight.setAttribute('transform', 'scale(-1 1)');
this.svgPathDark.setAttribute('transform', 'translate(1,1) scale(-1 1)');
};
/**
* Apply the stored colours to the block's path, taking into account whether
* the paths belong to a shadow block.
* @param {boolean} isShadow True if the block is a shadow block.
* @package
*/
Blockly.geras.PathObject.prototype.applyColour = function(isShadow) {
if (isShadow) {
this.svgPathLight.style.display = 'none';
this.svgPathDark.setAttribute('fill', this.secondaryColour);
this.svgPath.setAttribute('stroke', 'none');
this.svgPath.setAttribute('fill', this.secondaryColour);
} else {
this.svgPathLight.style.display = '';
this.svgPathDark.style.display = '';
this.svgPath.setAttribute('stroke', 'none');
this.svgPathLight.setAttribute('stroke', this.tertiaryColour);
this.svgPathDark.setAttribute('fill', this.darkColour);
this.svgPath.setAttribute('fill', this.primaryColour);
}
};
/**
* @override
*/
Blockly.geras.PathObject.prototype.setColourFromTriplet = function(primary,
secondary, tertiary) {
Blockly.geras.PathObject.superClass_.setColourFromTriplet.call(this, primary,
secondary, tertiary);
this.darkColour = tertiary ||
Blockly.utils.colour.blend('#000', primary, 0.2);
};

View File

@@ -26,7 +26,6 @@ goog.provide('Blockly.geras.Renderer');
goog.require('Blockly.blockRendering');
goog.require('Blockly.blockRendering.Renderer');
goog.require('Blockly.geras.ConstantProvider');
goog.require('Blockly.geras.Colourer');
goog.require('Blockly.geras.Drawer');
goog.require('Blockly.geras.HighlightConstantProvider');
goog.require('Blockly.geras.PathObject');
@@ -107,17 +106,6 @@ Blockly.geras.Renderer.prototype.makePathObject = function(root) {
return new Blockly.geras.PathObject(root);
};
/**
* Create a new instance of a renderer path object.
* @param {!Blockly.BlockSvg} block The root SVG element.
* @param {!Blockly.geras.IPathObject} pathObject [description]
* @return {!Blockly.geras.Colourer} The renderer path object.
* @package
*/
Blockly.geras.Renderer.prototype.makeColourer = function(block,
pathObject) {
return new Blockly.geras.Colourer(block, pathObject);
};
/**
* Create a new instance of the renderer's highlight constant provider.

View File

@@ -211,3 +211,39 @@ Blockly.utils.colour.names = {
'white': '#ffffff',
'yellow': '#ffff00'
};
/**
* Parse a block colour from a number or string, as provided in a block
* definition.
* @param {number|string} colour HSV hue value (0 to 360), #RRGGBB string,
* or a message reference string pointing to one of those two values.
* @return {{hue: ?number, colour: string}} An object containing the colour as
* a #RRGGBB string, and the hue if the input was an HSV hue value.
*/
Blockly.utils.colour.parseBlockColour = function(colour) {
var dereferenced = (typeof colour == 'string') ?
Blockly.utils.replaceMessageReferences(colour) : colour;
var hue = Number(dereferenced);
if (!isNaN(hue) && 0 <= hue && hue <= 360) {
return {
hue: hue,
hex: Blockly.hueToHex(hue)
};
} else {
var hex = Blockly.utils.colour.parse(dereferenced);
if (hex) {
// Only store hue if colour is set as a hue.
return {
hue: null,
hex: hex
};
} else {
var errorMsg = 'Invalid colour: "' + dereferenced + '"';
if (colour != dereferenced) {
errorMsg += ' (from "' + colour + '")';
}
throw Error(errorMsg);
}
}
};

View File

@@ -29,7 +29,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
"message0": "stack block",
"previousStatement": null,
"nextStatement": null,
"style": "math_blocks"
"colour": "120"
},
{
"type": "test_basic_dummy",