diff --git a/core/block.js b/core/block.js index ffa17c753..3df892d47 100644 --- a/core/block.js +++ b/core/block.js @@ -41,6 +41,7 @@ goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); goog.require('goog.math.Coordinate'); +goog.require('goog.color'); /** @@ -881,6 +882,46 @@ Blockly.Block.prototype.getColourTertiary = function() { return this.colourTertiary_; }; +/** + * Get the shadow colour of a block. + * @return {?string} #RRGGBB string. + */ +Blockly.Block.prototype.getColourShadow = function() { + var colourSecondary = this.getColourSecondary(); + if (colourSecondary) { + return colourSecondary; + } + var rgb = goog.color.hexToRgb(this.getColour()); + rgb = goog.color.lighten(rgb, 0.6); + return goog.color.rgbArrayToHex(rgb); +}; + +/** + * Get the border colour(s) of a block. + * @return {{colourDark, colourLight, colourBorder}} An object containing + * colour values for the border(s) of the block. If the block is using a + * style the colourBorder will be defined and equal to the tertiary colour + * of the style (#RRGGBB string). Otherwise the colourDark and colourLight + * attributes will be defined (#RRGGBB strings). + * @package + */ +Blockly.Block.prototype.getColourBorder = function() { + var colourTertiary = this.getColourTertiary(); + if (colourTertiary) { + return { + colourBorder: colourTertiary, + colourLight: null, + colourDark: null + }; + } + var rgb = goog.color.hexToRgb(this.getColour()); + return { + colourBorder: null, + colourLight: goog.color.rgbArrayToHex(goog.color.lighten(rgb, 0.3)), + colourDark: goog.color.rgbArrayToHex(goog.color.darken(rgb, 0.2)) + }; +}; + /** * Get the name of the block style. * @return {?string} Name of the block style. diff --git a/core/block_svg.js b/core/block_svg.js index a997d1884..ea5b51aa7 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -941,74 +941,59 @@ Blockly.BlockSvg.prototype.updateColour = function() { // Disabled blocks don't have colour. return; } - var hexColour = this.getColour(); - var colourSecondary = this.getColourSecondary(); - var colourTertiary = this.getColourTertiary(); - var rgb = goog.color.hexToRgb(hexColour); if (this.isShadow()) { - hexColour = this.setShadowColour_(rgb, colourSecondary); + this.setShadowColour_(); } else { - this.setBorderColour_(rgb, colourTertiary); + this.setBorderColour_(); + this.svgPath_.setAttribute('fill', this.getColour()); } - this.svgPath_.setAttribute('fill', hexColour); var icons = this.getIcons(); for (var i = 0; i < icons.length; i++) { icons[i].updateColour(); } - // Bump every dropdown to change its colour. - // TODO (#1456) for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { - field.forceRerender(); + field.updateColour(); } } }; /** * Sets the colour of the border. - * Removes the light and dark paths if a tertiary colour is defined. - * @param {!string} rgb Colour of the block. - * @param {?string} colourTertiary Colour of the border. + * Removes the light and dark paths if a border colour is defined. */ -Blockly.BlockSvg.prototype.setBorderColour_ = function(rgb, colourTertiary) { - if (colourTertiary) { - this.svgPathLight_.setAttribute('stroke', 'none'); - this.svgPathDark_.setAttribute('fill', 'none'); - this.svgPath_.setAttribute('stroke', colourTertiary); +Blockly.BlockSvg.prototype.setBorderColour_ = function() { + var borderColours = this.getColourBorder(); + if (borderColours.colourBorder) { + this.svgPathLight_.style.display = 'none'; + this.svgPathDark_.style.display = 'none'; + + this.svgPath_.setAttribute('stroke', borderColours.colourBorder); } else { this.svgPathLight_.style.display = ''; - var hexLight = goog.color.rgbArrayToHex(goog.color.lighten(rgb, 0.3)); - var hexDark = goog.color.rgbArrayToHex(goog.color.darken(rgb, 0.2)); - this.svgPathLight_.setAttribute('stroke', hexLight); - this.svgPathDark_.setAttribute('fill', hexDark); + this.svgPathDark_.style.display = ''; this.svgPath_.setAttribute('stroke', 'none'); + this.svgPathLight_.setAttribute('stroke', borderColours.colourLight); + this.svgPathDark_.setAttribute('fill', borderColours.colourDark); } }; /** * Sets the colour of shadow blocks. - * @param {!string} rgb Primary colour of the block. - * @param {?string} colourSecondary Colour for shadow block. - * @return {!string} The background colour of the block. + * @return {?string} The background colour of the block. */ -Blockly.BlockSvg.prototype.setShadowColour_ = function(rgb, colourSecondary) { - var hexColour; - if (colourSecondary) { - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.style.display = 'none'; - this.svgPath_.setAttribute('fill', colourSecondary); - hexColour = colourSecondary; - } else { - rgb = goog.color.lighten(rgb, 0.6); - hexColour = goog.color.rgbArrayToHex(rgb); - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.setAttribute('fill', hexColour); - } - return hexColour; +Blockly.BlockSvg.prototype.setShadowColour_ = function() { + this.svgPathLight_.style.display = 'none'; + this.svgPathDark_.style.display = 'none'; + this.svgPath_.setAttribute('stroke', 'none'); + + var shadowColour = this.getColourShadow(); + this.svgPath_.setAttribute('fill', shadowColour); + return shadowColour; }; /** diff --git a/core/field.js b/core/field.js index 8df264e6a..63bed0787 100644 --- a/core/field.js +++ b/core/field.js @@ -431,6 +431,15 @@ Blockly.Field.prototype.getSvgRoot = function() { return /** @type {!Element} */ (this.fieldGroup_); }; +/** + * Updates the field to match the colour/style of the block. Should only be + * called by BlockSvg.updateColour(). + * @package + */ +Blockly.Field.prototype.updateColour = function() { + // Non-abstract sub-classes may wish to implement this. See FieldDropdown. +}; + /** * Draws the border with the correct width. * Saves the computed width in a property. diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 0aadc0306..e6c6f267e 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -432,15 +432,26 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) { this.forceRerender(); }; +/** + * Updates the dropdown arrow to match the colour/style of the block. + * @package + */ +Blockly.FieldDropdown.prototype.updateColour = function() { + // Update arrow's colour. + if (this.sourceBlock_ && this.arrow_) { + if (this.sourceBlock_.isShadow()) { + this.arrow_.style.fill = this.sourceBlock_.getColourShadow(); + } else { + this.arrow_.style.fill = this.sourceBlock_.getColour(); + } + } +}; + /** * Draws the border with the correct width. * @private */ Blockly.FieldDropdown.prototype.render_ = function() { - if (this.sourceBlock_ && this.arrow_) { - // Update arrow's colour. - this.arrow_.style.fill = this.sourceBlock_.getColour(); - } var child; while ((child = this.textElement_.firstChild)) { this.textElement_.removeChild(child); diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index fb9da04df..1d5b47b0f 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -174,7 +174,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT } } ], - "colour": "230" + "style": "math_blocks", }, { "type": "test_fields_date", @@ -191,7 +191,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT } } ], - "colour": 230 + "style": "math_blocks", }, { "type": "test_fields_text_input", @@ -203,7 +203,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "text": "default" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -217,7 +217,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "checked": true } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -231,7 +231,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "colour": "#ff0000" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -245,7 +245,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "variable": "item" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -259,7 +259,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "text": "default" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, diff --git a/tests/playground.html b/tests/playground.html index 2c7deeb11..a46d88164 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -156,9 +156,36 @@ function addToolboxButtonCallbacks() { block.setFieldValue(text, 'LABEL'); } }; + var setRandomStyle = function(button) { + var blocks = button.workspace_.getAllBlocks(); + var styles = Object.keys(Blockly.getTheme().getAllBlockStyles()); + styles.splice(styles.indexOf(blocks[0].getStyleName()), 1); + var style = styles[Math.floor(Math.random() * styles.length)]; + for(var i = 0, block; block = blocks[i]; i++) { + block.setStyle(style); + } + }; + var toggleEnabled = function(button) { + var blocks = button.workspace_.getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + block.setEnabled(!block.isEnabled()); + } + }; + var toggleShadow = function(button) { + var blocks = button.workspace_.getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + block.setShadow(!block.isShadow()); + } + }; workspace.registerButtonCallback( - 'randomizeLabelText', randomizeLabelText); + 'setRandomStyle', setRandomStyle); + workspace.registerButtonCallback( + 'toggleEnabled', toggleEnabled); + workspace.registerButtonCallback( + 'toggleShadow', toggleShadow); + workspace.registerButtonCallback( + 'randomizeLabelText', randomizeLabelText); workspace.registerButtonCallback( 'addDynamicOption', Blockly.TestBlocks.addDynamicDropdownOption_); workspace.registerButtonCallback( @@ -1209,6 +1236,11 @@ h1 { + + + + +