一、背景
由于自带的下拉图标是给水平布局的block使用,放在垂直布局下显得别扭,而且下拉选择后回修改image字段的图片,这让我很不爽,所以在原来的基础上稍作修改,效果如下:
二、使用说明
(1)引入field_icon_dropdown.js到core文件夹中,代码在下文
(2)将field_icon_dropdown注册到Blockly中,这样在任意地方都可以使用,如果不想注入,直接用script标签引入也行,代码如下
goog.require('Blockly.FieldIconDropDown');
(3)block定义代码如下,下面代码是直接集成到一个完整block中,以设置彩灯块为例:
// ZE3P LED
Blockly.Blocks['ZE3P_led'] = {init: function () {this.jsonInit({"message0": "%1","args0": [{"type": "field_icon_dropdown","name": "COLOR","options": [{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_coral.svg',width: 48,height: 48,value: 'Red'},{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_green.svg',width: 48,height: 48,value: 'Green'},{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_blue.svg',width: 48,height: 48,value: 'Blue'},{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_orange.svg',width: 48,height: 48,value: 'Orange'},{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_yellow.svg',width: 48,height: 48,value: 'Yellow'},{src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_white.svg',width: 48,height: 48,value: 'White'},],}],"outputShape": Blockly.OUTPUT_SHAPE_ROUND,"output": "String","extensions": ["colours_looks"]});}
}
// ZE3P LED显示颜色
Blockly.Blocks['ZE3P_led_set_color'] = {init: function () {this.jsonInit({"message0": "%1%2","args0": [{"type": "field_image","src": Blockly.mainWorkspace.options.pathToMedia + "/extensions/ZE3P.png","width": 24,"height": 24},{"type": "field_vertical_separator"}],"message1": "设置彩灯 %1 显示 %2 ","args1": [{"type": "field_pin_dropdown","name": "INTERFACE","options": Blockly.Blocks.ZE3PInterfaceOptions,},{"type": "input_value","name": "COLOR",}],"category": Blockly.Categories.looks,"extensions": ["colours_looks", "shape_statement"]});}
};
(4)添加toolbox配置,代码如下:
<block type="ZE3P_led_set_color" id="ZE3P_led_set_color"><value name="COLOR"><shadow type="ZE3P_led"><field name="COLOR">Red</field></shadow></value>
</block>
(5)转码实现以python为例,代码如霞
// LED颜色
Blockly.Python['ZE3P_led'] = function (block) {let color = block.getFieldValue('COLOR') || 0;const code = "LedColor." + color;return [code, Blockly.Python.ORDER_ATOMIC];
};
// LED显示颜色
Blockly.Python['ZE3P_led_set_color'] = function (block) {const pin = block.getFieldValue('INTERFACE') || "";const color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC) || "";return `led.set_color(Interface.${pin}, ${color})\n`;
};
提示:如果采用注册方法,最好本地编译一下,使用javascript引入则不需要
三、效果展示
四、完整代码
完整field_icon_dropdown.js代码如下:
'use strict';goog.provide('Blockly.FieldIconDropDown');
goog.require('Blockly.DropDownDiv');/*** 构造器* @param icons* @constructor*/
Blockly.FieldIconDropDown = function (icons) {this.icons_ = icons;// Example:// [{src: '...', width: 20, height: 20, value: 'machine_value'}, ...]// 选择第一个为默认值const defaultValue = icons[0].value;Blockly.FieldIconDropDown.superClass_.constructor.call(this, defaultValue);this.addArgType('icon_dropdown');
};
goog.inherits(Blockly.FieldIconDropDown, Blockly.Field);/*** Json配置*/
Blockly.FieldIconDropDown.fromJson = function (element) {return new Blockly.FieldIconDropDown(element['options']);
};/*** 下拉面板宽度(不需要修改,3个图标宽度)* @type {number}* @const*/
Blockly.FieldIconDropDown.DROPDOWN_WIDTH = 168;/*** 颜色记录*/
Blockly.FieldIconDropDown.savedPrimary_ = null;/*** 初始化*/
Blockly.FieldIconDropDown.prototype.init = function (block) {if (this.fieldGroup_) {return;}// 下拉箭头大小const arrowSize = 12;// 重建domthis.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);// 字段宽度this.size_.width = 44;// 图标this.imageElement_ = Blockly.utils.createSvgElement('image', {'height': 24 + 'px','width': 24 + 'px','x': 4 + "px",'y': 4 + "px",}, this.fieldGroup_);this.setParentFieldImage(this.getSrcForValue(this.value_));// 下拉箭头位置this.arrowX_ = 32;this.arrowY_ = 10;if (block.RTL) {this.arrowX_ = -this.arrowX_ - arrowSize;}// 下拉图标this.arrowIcon_ = Blockly.utils.createSvgElement('image', {'height': arrowSize + 'px','width': arrowSize + 'px','transform': 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')'}, this.fieldGroup_);this.arrowIcon_.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'dropdown-arrow.svg');this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};/*** 鼠标放置样式*/
Blockly.FieldIconDropDown.prototype.CURSOR = 'default';/*** 设置值*/
Blockly.FieldIconDropDown.prototype.setValue = function (newValue) {if (newValue === null || newValue === this.value_) {return; // No change}if (this.sourceBlock_ && Blockly.Events.isEnabled()) {Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_, 'field', this.name, this.value_, newValue));}this.value_ = newValue;this.setParentFieldImage(this.getSrcForValue(this.value_));
};/*** 设置当前选择图片*/
Blockly.FieldIconDropDown.prototype.setParentFieldImage = function (src) {if (this.imageElement_ && src) {this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', src || '');}
};/*** 获取值*/
Blockly.FieldIconDropDown.prototype.getValue = function () {return this.value_;
};/*** 根据src获取值* @param value* @returns {*}*/
Blockly.FieldIconDropDown.prototype.getSrcForValue = function (value) {for (var i = 0, icon; icon = this.icons_[i]; i++) {if (icon.value === value) {return icon.src;}}
};/*** 下拉选择*/
Blockly.FieldIconDropDown.prototype.showEditor_ = function () {if (Blockly.DropDownDiv.hideIfOwner(this)) {return;}Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();// 构建下拉内容const contentDiv = Blockly.DropDownDiv.getContentDiv();// Accessibility propertiescontentDiv.setAttribute('role', 'menu');contentDiv.setAttribute('aria-haspopup', 'true');for (let i = 0, icon; icon = this.icons_[i]; i++) {// 按钮const button = document.createElement('button');button.setAttribute('id', ':' + i);button.setAttribute('role', 'menuitem');button.setAttribute('class', 'blocklyDropDownButton');button.title = icon.alt;button.style.width = icon.width + 'px';button.style.height = icon.height + 'px';let backgroundColor = this.sourceBlock_.getColour();if (icon.value === this.getValue()) {backgroundColor = this.sourceBlock_.getColourTertiary();button.setAttribute('aria-selected', 'true');}button.style.backgroundColor = backgroundColor;button.style.borderColor = this.sourceBlock_.getColourTertiary();// 事件Blockly.bindEvent_(button, 'click', this, this.buttonClick_);Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);Blockly.bindEvent_(button, 'mousedown', button, function (e) {this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');e.preventDefault();});Blockly.bindEvent_(button, 'mouseover', button, function () {this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');contentDiv.setAttribute('aria-activedescendant', this.id);});Blockly.bindEvent_(button, 'mouseout', button, function () {this.setAttribute('class', 'blocklyDropDownButton');contentDiv.removeAttribute('aria-activedescendant');});// 图标const buttonImg = document.createElement('img');buttonImg.src = icon.src;button.setAttribute('data-value', icon.value);buttonImg.setAttribute('data-value', icon.value);button.appendChild(buttonImg);contentDiv.appendChild(button);}contentDiv.style.width = Blockly.FieldIconDropDown.DROPDOWN_WIDTH + 'px';// 设置颜色Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());Blockly.DropDownDiv.setCategory(this.sourceBlock_.parentBlock_.getCategory());this.savedPrimary_ = this.sourceBlock_.getColour();this.sourceBlock_.setColour(this.sourceBlock_.getColourSecondary(),this.sourceBlock_.getColourSecondary(),this.sourceBlock_.getColourTertiary());const scale = this.sourceBlock_.workspace.scale;const secondaryYOffset = (-(Blockly.BlockSvg.MIN_BLOCK_Y * scale) - (Blockly.BlockSvg.FIELD_Y_OFFSET * scale));const renderedPrimary = Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_, this.onHide_.bind(this), secondaryYOffset);if (!renderedPrimary) {const arrowX = this.arrowX_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5 + 1;const arrowY = this.arrowY_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5;this.arrowIcon_.setAttribute('transform', 'translate(' + arrowX + ',' + arrowY + ') rotate(180)');}
};/*** 点击按钮*/
Blockly.FieldIconDropDown.prototype.buttonClick_ = function (e) {const value = e.target.getAttribute('data-value');this.setValue(value);Blockly.DropDownDiv.hide();
};/*** 关闭下拉面板时回掉*/
Blockly.FieldIconDropDown.prototype.onHide_ = function () {if (this.sourceBlock_) {this.sourceBlock_.setColour(this.savedPrimary_,this.sourceBlock_.getColourSecondary(),this.sourceBlock_.getColourTertiary());}Blockly.DropDownDiv.content_.removeAttribute('role');Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');this.arrowIcon_.setAttribute('transform', 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')');
};Blockly.Field.register('field_icon_dropdown', Blockly.FieldIconDropDown);
五、关于我
作者:陆志敏
联系:761324428@qq.com