From 372a12916d53a35f5022c266c367f4dbc59344a4 Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Wed, 24 May 2023 12:25:33 -0400 Subject: [PATCH] [blocks] display - matrix - add FieldMatrixSingle --- all_blocks.md | 4 +- ...display-matrix-add-FieldMatrixSingle.patch | 707 ++++++++++++++++++ 2 files changed, 709 insertions(+), 2 deletions(-) create mode 100644 patches/blocks/0004-display-matrix-add-FieldMatrixSingle.patch diff --git a/all_blocks.md b/all_blocks.md index 717a062..9412af2 100644 --- a/all_blocks.md +++ b/all_blocks.md @@ -29,10 +29,10 @@ todo: light.animate - DONE `turn display off` - transpiled: `hub.display.off()` -- `set (m! row, col) to (brightness %) brightness` +- DONE `set (m! row, col) to (brightness %) brightness` - transpiled: `hub.display.pixel(row, col, brightness)` -- `show (m! picutre) on display` +- DONE `show (m! picutre) on display` - transpiled: `hub.display.icon(picture)` todo: display.animate diff --git a/patches/blocks/0004-display-matrix-add-FieldMatrixSingle.patch b/patches/blocks/0004-display-matrix-add-FieldMatrixSingle.patch new file mode 100644 index 0000000..fa35f73 --- /dev/null +++ b/patches/blocks/0004-display-matrix-add-FieldMatrixSingle.patch @@ -0,0 +1,707 @@ +From 96e9a57f0af460032f345cf0f4f5ca2ead4433e4 Mon Sep 17 00:00:00 2001 +From: c0repwn3r +Date: Wed, 24 May 2023 12:24:47 -0400 +Subject: [PATCH] display - matrix - add FieldMatrixSingle + +--- + blocks_common/matrix.js | 23 +- + blocks_vertical/default_toolbox.js | 19 + + blocks_vertical/display.js | 42 +++ + core/field_matrix.js | 548 ++++++++++++++++++++++++++++- + msg/messages.js | 2 + + 5 files changed, 632 insertions(+), 2 deletions(-) + +diff --git a/blocks_common/matrix.js b/blocks_common/matrix.js +index 8945f8b0..6af2f844 100644 +--- a/blocks_common/matrix.js ++++ b/blocks_common/matrix.js +@@ -48,7 +48,28 @@ Blockly.Blocks['matrix'] = { + ], + "outputShape": Blockly.OUTPUT_SHAPE_ROUND, + "output": "Number", +- "extensions": ["colours_pen"] ++ "extensions": ["colours_display"] ++ }); ++ } ++}; ++ ++Blockly.Blocks['matrix_single'] = { ++ /** ++ * Block for matrix value. ++ * @this Blockly.Block ++ */ ++ init: function() { ++ this.jsonInit({ ++ "message0": "%1", ++ "args0": [ ++ { ++ "type": "field_matrix_single", ++ "name": "MATRIX" ++ } ++ ], ++ "outputShape": Blockly.OUTPUT_SHAPE_ROUND, ++ "output": "Number", ++ "extensions": ["colours_display"] + }); + } + }; +diff --git a/blocks_vertical/default_toolbox.js b/blocks_vertical/default_toolbox.js +index 781a5f46..2807cfcd 100644 +--- a/blocks_vertical/default_toolbox.js ++++ b/blocks_vertical/default_toolbox.js +@@ -51,6 +51,25 @@ Blockly.Blocks.defaultToolbox = '' + ++ '' + ++ '' + ++ '' + ++ '0000000010000000' + ++ '' + ++ '' + ++ '' + ++ '' + ++ '100' + ++ '' + ++ '' + ++ '' + ++ '' + ++ '' + ++ '' + ++ '0101001010000001000101110' + ++ '' + ++ '' + ++ '' + + '' + + '' + + '' + +diff --git a/blocks_vertical/display.js b/blocks_vertical/display.js +index 22338b5e..5977c46a 100644 +--- a/blocks_vertical/display.js ++++ b/blocks_vertical/display.js +@@ -61,3 +61,45 @@ Blockly.Blocks['hub_display_string'] = { + }); + } + }; ++ ++Blockly.Blocks['hub_display_pixel'] = { ++ /** ++ * @this Blockly.Block ++ */ ++ init: function() { ++ this.jsonInit({ ++ "message0": Blockly.Msg.HUB_DISPLAY_PIXEL, ++ "args0": [ ++ { ++ "type": "input_value", ++ "name": "PIXEL" ++ }, ++ { ++ "type": "input_value", ++ "name": "BRIGHTNESS" ++ } ++ ], ++ "category": Blockly.Categories.display, ++ "extensions": ["colours_display", "shape_statement"] ++ }); ++ } ++}; ++ ++Blockly.Blocks['hub_display_icon'] = { ++ /** ++ * @this Blockly.Block ++ */ ++ init: function() { ++ this.jsonInit({ ++ "message0": Blockly.Msg.HUB_DISPLAY_ICON, ++ "args0": [ ++ { ++ "type": "input_value", ++ "name": "ICON" ++ } ++ ], ++ "category": Blockly.Categories.display, ++ "extensions": ["colours_display", "shape_statement"] ++ }); ++ } ++}; +diff --git a/core/field_matrix.js b/core/field_matrix.js +index e8410e30..19c0be9c 100644 +--- a/core/field_matrix.js ++++ b/core/field_matrix.js +@@ -25,7 +25,8 @@ + */ + 'use strict'; + +-goog.provide('Blockly.FieldMatrix'); ++goog.provide('Blockly.FieldMatrix') ++goog.provide('Blockly.FieldMatrixSingle'); + + goog.require('Blockly.DropDownDiv'); + +@@ -563,4 +564,549 @@ Blockly.FieldMatrix.prototype.dispose_ = function() { + }; + }; + ++/** ++ * Class for a matrix field with only one selected pixel at a time. ++ * @param {number} matrix The default matrix value represented by a 25-bit integer. ++ * @extends {Blockly.Field} ++ * @constructor ++ */ ++Blockly.FieldMatrixSingle = function(matrix) { ++ Blockly.FieldMatrixSingle.superClass_.constructor.call(this, matrix); ++ this.addArgType('matrix'); ++ /** ++ * Array of SVGElement for matrix thumbnail image on block field. ++ * @type {!Array} ++ * @private ++ */ ++ this.ledThumbNodes_ = []; ++ /** ++ * Array of SVGElement for matrix editor in dropdown menu. ++ * @type {!Array} ++ * @private ++ */ ++ this.ledButtons_ = []; ++ /** ++ * String for storing current matrix value. ++ * @type {!String] ++ * @private ++ */ ++ this.matrix_ = ''; ++ /** ++ * SVGElement for LED matrix in editor. ++ * @type {?SVGElement} ++ * @private ++ */ ++ this.matrixStage_ = null; ++ /** ++ * SVG image for dropdown arrow. ++ * @type {?SVGElement} ++ * @private ++ */ ++ this.arrow_ = null; ++ /** ++ * String indicating matrix paint style. ++ * value can be [null, 'fill', 'clear']. ++ * @type {?String} ++ * @private ++ */ ++ this.paintStyle_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the field is selected. ++ * @type {!Array} ++ * @private ++ */ ++ this.mouseDownWrapper_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the clear button editor button is selected. ++ * @type {!Array} ++ * @private ++ */ ++ this.clearButtonWrapper_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the fill button editor button is selected. ++ * @type {!Array} ++ * @private ++ */ ++ this.fillButtonWrapper_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the matrix editor is touched. ++ * @type {!Array} ++ * @private ++ */ ++ this.matrixTouchWrapper_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the matrix editor touch event moves. ++ * @type {!Array} ++ * @private ++ */ ++ this.matrixMoveWrapper_ = null; ++ /** ++ * Touch event wrapper. ++ * Runs when the matrix editor is released. ++ * @type {!Array} ++ * @private ++ */ ++ this.matrixReleaseWrapper_ = null; ++}; ++goog.inherits(Blockly.FieldMatrixSingle, Blockly.Field); ++ ++/** ++ * Construct a FieldMatrixSingle from a JSON arg object. ++ * @param {!Object} options A JSON object with options (matrix). ++ * @returns {!Blockly.FieldMatrixSingle} The new field instance. ++ * @package ++ * @nocollapse ++ */ ++Blockly.FieldMatrixSingle.fromJson = function(options) { ++ return new Blockly.FieldMatrixSingle(options['matrix']); ++}; ++ ++/** ++ * Fixed size of the matrix thumbnail in the input field, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.THUMBNAIL_SIZE = 26; ++ ++/** ++ * Fixed size of each matrix thumbnail node, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.THUMBNAIL_NODE_SIZE = 4; ++ ++/** ++ * Fixed size of each matrix thumbnail node, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.THUMBNAIL_NODE_PAD = 1; ++ ++/** ++ * Fixed size of arrow icon in drop down menu, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.ARROW_SIZE = 12; ++ ++/** ++ * Fixed size of each button inside the 5x5 matrix, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE = 18; ++ ++/** ++ * Fixed corner radius for 5x5 matrix buttons, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.MATRIX_NODE_RADIUS = 4; ++ ++/** ++ * Fixed padding for 5x5 matrix buttons, in px. ++ * @type {number} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.MATRIX_NODE_PAD = 5; ++ ++/** ++ * String with 25 '0' chars. ++ * Used for clearing a matrix or filling an LED node array. ++ * @type {string} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.ZEROS = '0000000000000000000000000'; ++ ++/** ++ * String with 25 '1' chars. ++ * Used for filling a matrix. ++ * @type {string} ++ * @const ++ */ ++Blockly.FieldMatrixSingle.ONES = '1111111111111111111111111'; ++ ++/** ++ * Called when the field is placed on a block. ++ * @param {Block} block The owning block. ++ */ ++Blockly.FieldMatrixSingle.prototype.init = function() { ++ if (this.fieldGroup_) { ++ // Matrix menu has already been initialized once. ++ return; ++ } ++ ++ // Build the DOM. ++ this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); ++ this.size_.width = Blockly.FieldMatrixSingle.THUMBNAIL_SIZE + ++ Blockly.FieldMatrixSingle.ARROW_SIZE + (Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5); ++ ++ this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); ++ ++ var thumbX = Blockly.BlockSvg.DROPDOWN_ARROW_PADDING / 2; ++ var thumbY = (this.size_.height - Blockly.FieldMatrixSingle.THUMBNAIL_SIZE) / 2; ++ var thumbnail = Blockly.utils.createSvgElement('g', { ++ 'transform': 'translate(' + thumbX + ', ' + thumbY + ')', ++ 'pointer-events': 'bounding-box', 'cursor': 'pointer' ++ }, this.fieldGroup_); ++ this.ledThumbNodes_ = []; ++ var nodeSize = Blockly.FieldMatrixSingle.THUMBNAIL_NODE_SIZE; ++ var nodePad = Blockly.FieldMatrixSingle.THUMBNAIL_NODE_PAD; ++ for (var i = 0; i < 5; i++) { ++ for (var n = 0; n < 5; n++) { ++ var attr = { ++ 'x': ((nodeSize + nodePad) * n) + nodePad, ++ 'y': ((nodeSize + nodePad) * i) + nodePad, ++ 'width': nodeSize, 'height': nodeSize, ++ 'rx': nodePad, 'ry': nodePad ++ }; ++ this.ledThumbNodes_.push( ++ Blockly.utils.createSvgElement('rect', attr, thumbnail) ++ ); ++ } ++ thumbnail.style.cursor = 'default'; ++ this.updateMatrix_(); ++ } ++ ++ if (!this.arrow_) { ++ var arrowX = Blockly.FieldMatrixSingle.THUMBNAIL_SIZE + ++ Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5; ++ var arrowY = (this.size_.height - Blockly.FieldMatrixSingle.ARROW_SIZE) / 2; ++ this.arrow_ = Blockly.utils.createSvgElement('image', { ++ 'height': Blockly.FieldMatrixSingle.ARROW_SIZE + 'px', ++ 'width': Blockly.FieldMatrixSingle.ARROW_SIZE + 'px', ++ 'transform': 'translate(' + arrowX + ', ' + arrowY + ')' ++ }, this.fieldGroup_); ++ this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink', ++ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + ++ 'dropdown-arrow.svg'); ++ this.arrow_.style.cursor = 'default'; ++ } ++ ++ this.mouseDownWrapper_ = Blockly.bindEventWithChecks_( ++ this.getClickTarget_(), 'mousedown', this, this.onMouseDown_); ++}; ++ ++/** ++ * Set the value for this matrix menu. ++ * @param {string} matrix The new matrix value represented by a 25-bit integer. ++ * @override ++ */ ++Blockly.FieldMatrixSingle.prototype.setValue = function(matrix) { ++ if (!matrix || matrix === this.matrix_) { ++ return; // No change ++ } ++ if (this.sourceBlock_ && Blockly.Events.isEnabled()) { ++ Blockly.Events.fire(new Blockly.Events.Change( ++ this.sourceBlock_, 'field', this.name, this.matrix_, matrix)); ++ } ++ matrix = matrix + Blockly.FieldMatrixSingle.ZEROS.substr(0, 25 - matrix.length); ++ this.matrix_ = matrix; ++ this.updateMatrix_(); ++}; ++ ++/** ++ * Get the value from this matrix menu. ++ * @return {string} Current matrix value. ++ */ ++Blockly.FieldMatrixSingle.prototype.getValue = function() { ++ return String(this.matrix_); ++}; ++ ++/** ++ * Show the drop-down menu for editing this field. ++ * @private ++ */ ++Blockly.FieldMatrixSingle.prototype.showEditor_ = function() { ++ // If there is an existing drop-down someone else owns, hide it immediately and clear it. ++ Blockly.DropDownDiv.hideWithoutAnimation(); ++ Blockly.DropDownDiv.clearContent(); ++ var div = Blockly.DropDownDiv.getContentDiv(); ++ // Build the SVG DOM. ++ var matrixSize = (Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE * 5) + ++ (Blockly.FieldMatrixSingle.MATRIX_NODE_PAD * 6); ++ this.matrixStage_ = Blockly.utils.createSvgElement('svg', { ++ 'xmlns': 'http://www.w3.org/2000/svg', ++ 'xmlns:html': 'http://www.w3.org/1999/xhtml', ++ 'xmlns:xlink': 'http://www.w3.org/1999/xlink', ++ 'version': '1.1', ++ 'height': matrixSize + 'px', ++ 'width': matrixSize + 'px' ++ }, div); ++ // Create the 5x5 matrix ++ this.ledButtons_ = []; ++ for (var i = 0; i < 5; i++) { ++ for (var n = 0; n < 5; n++) { ++ var x = (Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE * n) + ++ (Blockly.FieldMatrixSingle.MATRIX_NODE_PAD * (n + 1)); ++ var y = (Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE * i) + ++ (Blockly.FieldMatrixSingle.MATRIX_NODE_PAD * (i + 1)); ++ var attr = { ++ 'x': x + 'px', 'y': y + 'px', ++ 'width': Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE, ++ 'height': Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE, ++ 'rx': Blockly.FieldMatrixSingle.MATRIX_NODE_RADIUS, ++ 'ry': Blockly.FieldMatrixSingle.MATRIX_NODE_RADIUS ++ }; ++ var led = Blockly.utils.createSvgElement('rect', attr, this.matrixStage_); ++ this.matrixStage_.appendChild(led); ++ this.ledButtons_.push(led); ++ } ++ } ++ // Div for lower button menu ++ /* ++ var buttonDiv = document.createElement('div'); ++ // Button to clear matrix ++ var clearButtonDiv = document.createElement('div'); ++ clearButtonDiv.className = 'scratchMatrixButtonDiv'; ++ var clearButton = this.createButton_(this.sourceBlock_.colourSecondary_); ++ clearButtonDiv.appendChild(clearButton); ++ // Button to fill matrix ++ ++ var fillButtonDiv = document.createElement('div'); ++ fillButtonDiv.className = 'scratchMatrixButtonDiv'; ++ var fillButton = this.createButton_('#FFFFFF'); ++ fillButtonDiv.appendChild(fillButton); ++ ++ ++ ++ buttonDiv.appendChild(clearButtonDiv); ++ buttonDiv.appendChild(fillButtonDiv); ++ div.appendChild(buttonDiv); ++ ++ ++ */ ++ ++ Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), ++ this.sourceBlock_.getColourTertiary()); ++ Blockly.DropDownDiv.setCategory(this.sourceBlock_.getCategory()); ++ Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_); ++ ++ this.matrixTouchWrapper_ = ++ Blockly.bindEvent_(this.matrixStage_, 'mousedown', this, this.onMouseDown); ++ //this.clearButtonWrapper_ = ++ // Blockly.bindEvent_(clearButton, 'click', this, this.clearMatrix_); ++ //this.fillButtonWrapper_ = ++ // Blockly.bindEvent_(fillButton, 'click', this, this.fillMatrix_); ++ ++ // Update the matrix for the current value ++ this.updateMatrix_(); ++ ++}; ++ ++this.nodeCallback_ = function(e, num) { ++ console.log(num); ++}; ++ ++/** ++ * Make an svg object that resembles a 3x3 matrix to be used as a button. ++ * @param {string} fill The color to fill the matrix nodes. ++ * @return {SvgElement} The button svg element. ++ */ ++Blockly.FieldMatrixSingle.prototype.createButton_ = function(fill) { ++ var button = Blockly.utils.createSvgElement('svg', { ++ 'xmlns': 'http://www.w3.org/2000/svg', ++ 'xmlns:html': 'http://www.w3.org/1999/xhtml', ++ 'xmlns:xlink': 'http://www.w3.org/1999/xlink', ++ 'version': '1.1', ++ 'height': Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE + 'px', ++ 'width': Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE + 'px' ++ }); ++ var nodeSize = Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE / 4; ++ var nodePad = Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE / 16; ++ for (var i = 0; i < 3; i++) { ++ for (var n = 0; n < 3; n++) { ++ Blockly.utils.createSvgElement('rect', { ++ 'x': ((nodeSize + nodePad) * n) + nodePad, ++ 'y': ((nodeSize + nodePad) * i) + nodePad, ++ 'width': nodeSize, 'height': nodeSize, ++ 'rx': nodePad, 'ry': nodePad, ++ 'fill': fill ++ }, button); ++ } ++ } ++ return button; ++}; ++ ++/** ++ * Redraw the matrix with the current value. ++ * @private ++ */ ++Blockly.FieldMatrixSingle.prototype.updateMatrix_ = function() { ++ for (var i = 0; i < this.matrix_.length; i++) { ++ if (this.matrix_[i] === '0') { ++ this.fillMatrixNode_(this.ledButtons_, i, this.sourceBlock_.colourSecondary_); ++ this.fillMatrixNode_(this.ledThumbNodes_, i, this.sourceBlock_.colour_); ++ } else { ++ this.fillMatrixNode_(this.ledButtons_, i, '#FFFFFF'); ++ this.fillMatrixNode_(this.ledThumbNodes_, i, '#FFFFFF'); ++ } ++ } ++}; ++ ++/** ++ * Clear the matrix. ++ * @param {!Event} e Mouse event. ++ */ ++Blockly.FieldMatrixSingle.prototype.clearMatrix_ = function(e) { ++ if (e.button != 0) return; ++ this.setValue(Blockly.FieldMatrixSingle.ZEROS); ++}; ++ ++/** ++ * Fill the matrix. ++ * @param {!Event} e Mouse event. ++ */ ++Blockly.FieldMatrixSingle.prototype.fillMatrix_ = function(e) { ++ if (e.button != 0) return; ++ this.setValue(Blockly.FieldMatrixSingle.ONES); ++}; ++ ++/** ++ * Fill matrix node with specified colour. ++ * @param {!Array} node The array of matrix nodes. ++ * @param {!number} index The index of the matrix node. ++ * @param {!string} fill The fill colour in '#rrggbb' format. ++ */ ++Blockly.FieldMatrixSingle.prototype.fillMatrixNode_ = function(node, index, fill) { ++ if (!node || !node[index] || !fill) return; ++ node[index].setAttribute('fill', fill); ++}; ++ ++Blockly.FieldMatrixSingle.prototype.setLEDNode_ = function(led, state) { ++ if (led < 0 || led > 24) return; ++ var matrix = this.matrix_.substr(0, led) + state + this.matrix_.substr(led + 1); ++ this.setValue(matrix); ++}; ++ ++Blockly.FieldMatrixSingle.prototype.fillLEDNode_ = function(led) { ++ if (led < 0 || led > 24) return; ++ this.setLEDNode_(led, '1'); ++}; ++ ++Blockly.FieldMatrixSingle.prototype.clearLEDNode_ = function(led) { ++ if (led < 0 || led > 24) return; ++ this.setLEDNode_(led, '0'); ++}; ++ ++Blockly.FieldMatrixSingle.prototype.toggleLEDNode_ = function(led, e) { ++ this.clearMatrix_(e); ++ if (led < 0 || led > 24) return; ++ if (this.matrix_.charAt(led) === '0') { ++ this.setLEDNode_(led, '1'); ++ } else { ++ this.setLEDNode_(led, '0'); ++ } ++}; ++ ++/** ++ * Toggle matrix nodes on and off. ++ * @param {!Event} e Mouse event. ++ */ ++Blockly.FieldMatrixSingle.prototype.onMouseDown = function(e) { ++ this.matrixMoveWrapper_ = ++ Blockly.bindEvent_(document.body, 'mousemove', this, this.onMouseMove); ++ this.matrixReleaseWrapper_ = ++ Blockly.bindEvent_(document.body, 'mouseup', this, this.onMouseUp); ++ var ledHit = this.checkForLED_(e); ++ if (ledHit > -1) { ++ if (this.matrix_.charAt(ledHit) === '0') { ++ this.paintStyle_ = 'fill'; ++ } else { ++ this.paintStyle_ = 'clear'; ++ } ++ this.toggleLEDNode_(ledHit, e); ++ this.updateMatrix_(); ++ } else { ++ this.paintStyle_ = null; ++ } ++}; ++ ++/** ++ * Unbind mouse move event and clear the paint style. ++ * @param {!Event} e Mouse move event. ++ */ ++Blockly.FieldMatrixSingle.prototype.onMouseUp = function(e) { ++ Blockly.unbindEvent_(this.matrixMoveWrapper_); ++ Blockly.unbindEvent_(this.matrixReleaseWrapper_); ++ this.paintStyle_ = null; ++}; ++ ++/** ++ * Toggle matrix nodes on and off by dragging mouse. ++ * @param {!Event} e Mouse move event. ++ */ ++Blockly.FieldMatrixSingle.prototype.onMouseMove = function(e) { ++ e.preventDefault(); ++ if (this.paintStyle_) { ++ var led = this.checkForLED_(e); ++ if (led < 0) return; ++ if (this.paintStyle_ === 'clear') { ++ this.clearLEDNode_(led); ++ } else if (this.paintStyle_ === 'fill') { ++ this.clearMatrix_(e); ++ this.fillLEDNode_(led); ++ } ++ } ++}; ++ ++/** ++ * Check if mouse coordinates collide with a matrix node. ++ * @param {!Event} e Mouse move event. ++ * @return {number} The matching matrix node or -1 for none. ++ */ ++Blockly.FieldMatrixSingle.prototype.checkForLED_ = function(e) { ++ var bBox = this.matrixStage_.getBoundingClientRect(); ++ var nodeSize = Blockly.FieldMatrixSingle.MATRIX_NODE_SIZE; ++ var nodePad = Blockly.FieldMatrixSingle.MATRIX_NODE_PAD; ++ var dx = e.clientX - bBox.left; ++ var dy = e.clientY - bBox.top; ++ var min = nodePad / 2; ++ var max = bBox.width - (nodePad / 2); ++ if (dx < min || dx > max || dy < min || dy > max) { ++ return -1; ++ } ++ var xDiv = Math.trunc((dx - nodePad / 2) / (nodeSize + nodePad)); ++ var yDiv = Math.trunc((dy - nodePad / 2) / (nodeSize + nodePad)); ++ return xDiv + (yDiv * nodePad); ++}; ++ ++/** ++ * Clean up this FieldMatrixSingle, as well as the inherited Field. ++ * @return {!Function} Closure to call on destruction of the WidgetDiv. ++ * @private ++ */ ++Blockly.FieldMatrixSingle.prototype.dispose_ = function() { ++ var thisField = this; ++ return function() { ++ Blockly.FieldMatrixSingle.superClass_.dispose_.call(thisField)(); ++ thisField.matrixStage_ = null; ++ if (thisField.mouseDownWrapper_) { ++ Blockly.unbindEvent_(thisField.mouseDownWrapper_); ++ } ++ if (thisField.matrixTouchWrapper_) { ++ Blockly.unbindEvent_(thisField.matrixTouchWrapper_); ++ } ++ if (thisField.matrixReleaseWrapper_) { ++ Blockly.unbindEvent_(thisField.matrixReleaseWrapper_); ++ } ++ if (thisField.matrixMoveWrapper_) { ++ Blockly.unbindEvent_(thisField.matrixMoveWrapper_); ++ } ++ if (thisField.clearButtonWrapper_) { ++ Blockly.unbindEvent_(thisField.clearButtonWrapper_); ++ } ++ if (thisField.fillButtonWrapper_) { ++ Blockly.unbindEvent_(thisField.fillButtonWrapper_); ++ } ++ }; ++}; ++ ++ + Blockly.Field.register('field_matrix', Blockly.FieldMatrix); ++Blockly.Field.register('field_matrix_single', Blockly.FieldMatrixSingle); +diff --git a/msg/messages.js b/msg/messages.js +index feb70bcd..b9cd5997 100644 +--- a/msg/messages.js ++++ b/msg/messages.js +@@ -375,6 +375,8 @@ Blockly.Msg.HUB_DISPLAY_OFF = 'turn display off'; + Blockly.Msg.HUB_DISPLAY_NUM = 'show digits %1 on display'; + Blockly.Msg.HUB_DISPLAY_CHAR = 'show char %1 on display'; + Blockly.Msg.HUB_DISPLAY_STRING = 'scroll %1 across display'; ++Blockly.Msg.HUB_DISPLAY_PIXEL = 'set %1 to %2 brightness'; ++Blockly.Msg.HUB_DISPLAY_ICON = 'show %1 on display'; + + Blockly.Msg.HUB_INPUT_ISBUTTONPRESSED = 'is %1 button pressed?'; + +-- +2.40.1 +