update to pxt 5 and pxt-common-packages 6 (#934)

* bump pxt

* fix build issues

* Auto-gen of projects/summary

* removing feild editors moved to pxt

* various typing fixes

* more typing fixes

* fixing various typing issues

* Start on integration of new pxt

* serial number fixes

* gc-ify MMap object

* Re-build generated files

* fix console listeners

* clear lf() warnings

* More generated files

* also auto-generated

* Compilation fixes

* fix merge

* mostly fixing blocks

* fix sim

* fix field motors

* enable a few features

* moving to tsx

* try to fix edtiro compilation

* more defs

* removing commands

* removing extra $

* fix blockly warning

* hiding images

* enabling more pxt features

* hide images

* setup autorun

* add lock on target_reset

* update deps

* return trylock result

* updated pxt

* rename video section

* add alpha channel

* upgraded pxt

* bump pxt/version

* removed alpha ref

* var ceanup

* don't do major bump
This commit is contained in:
Michał Moskal
2019-10-08 21:57:55 -07:00
committed by Peli de Halleux
parent ba94322d4c
commit c5cec3a6ba
44 changed files with 1147 additions and 1221 deletions

View File

@ -3,9 +3,7 @@
import { FieldPorts } from "./field_ports";
import { FieldMotors } from "./field_motors";
import { FieldSpeed } from "./field_speed";
import { FieldBrickButtons } from "./field_brickbuttons";
import { FieldTurnRatio } from "./field_turnratio";
import { FieldColorEnum } from "./field_color";
import { FieldMusic } from "./field_music";
@ -19,15 +17,9 @@ pxt.editor.initFieldExtensionsAsync = function (opts: pxt.editor.FieldExtensionO
}, {
selector: "motors",
editor: FieldMotors
}, {
selector: "speed",
editor: FieldSpeed
}, {
selector: "brickbuttons",
editor: FieldBrickButtons
}, {
selector: "turnratio",
editor: FieldTurnRatio
}, {
selector: "colorenum",
editor: FieldColorEnum

View File

@ -121,17 +121,17 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
Blockly.DropDownDiv.setColour('#ffffff', '#dddddd');
// Calculate positioning based on the field position.
var scale = this.sourceBlock_.workspace.scale;
var bBox = { width: this.size_.width, height: this.size_.height };
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale;
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale;
bBox.height *= scale;
var position = this.fieldGroup_.getBoundingClientRect();
var primaryX = position.left + bBox.width / 2;
var primaryY = position.top + bBox.height;
var secondaryX = primaryX;
var secondaryY = position.top;
let position = this.fieldGroup_.getBoundingClientRect();
let primaryX = position.left + bBox.width / 2;
let primaryY = position.top + bBox.height;
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
}
@ -152,9 +152,10 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
* Callback for when the drop-down is hidden.
*/
private onHide_ = function () {
Blockly.DropDownDiv.content_.removeAttribute('role');
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
Blockly.DropDownDiv.getContentDiv().style.width = '';
const content = Blockly.DropDownDiv.getContentDiv();
content.removeAttribute('role');
content.removeAttribute('aria-haspopup');
content.removeAttribute('aria-activedescendant');
(content as HTMLElement).style.width = '';
};
}

View File

@ -44,7 +44,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
* @return {string} Current colour in '#rrggbb' format.
*/
getValue(opt_asHex?: boolean) {
var colour = this.mapColour(this.colour_);
const colour = this.mapColour(this.value_);
if (!opt_asHex && colour.indexOf('#') > -1) {
return `0x${colour.replace(/^#/, '')}`;
}
@ -56,13 +56,13 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
* @param {string} colour The new colour in '#rrggbb' format.
*/
setValue(colorStr: string) {
var colour = this.mapEnum(colorStr);
let colour = this.mapEnum(colorStr);
if (this.sourceBlock_ && Blockly.Events.isEnabled() &&
this.colour_ != colour) {
this.value_ != colour) {
Blockly.Events.fire(new (Blockly as any).Events.BlockChange(
this.sourceBlock_, 'field', this.name, this.colour_, colour));
this.sourceBlock_, 'field', this.name, this.value_, colour));
}
this.colour_ = colour;
this.value_ = colour;
if (this.sourceBlock_) {
this.sourceBlock_.setColour(colour, colour, colour);
}

View File

@ -46,31 +46,31 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
(this as any).arrowX_ = 0;
/** @type {Number} */
this.arrowY_ = 11;
this.arrow_ = Blockly.utils.createSvgElement('image', {
this.arrow_ = Blockly.utils.dom.createSvgElement('image', {
'height': (this as any).arrowSize_ + 'px',
'width': (this as any).arrowSize_ + 'px'
});
}, null);
this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI);
this.arrow2_ = Blockly.utils.createSvgElement('image', {
this.arrow2_ = <SVGImageElement>Blockly.utils.dom.createSvgElement('image', {
'height': (this as any).arrowSize_ + 'px',
'width': (this as any).arrowSize_ + 'px'
});
}, null);
this.arrow2_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', (Blockly.FieldDropdown as any).DROPDOWN_SVG_DATAURI);
(this as any).className_ += ' blocklyDropdownText';
// Build the DOM.
this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
if (!this.visible_) {
(this.fieldGroup_ as any).style.display = 'none';
}
// Adjust X to be flipped for RTL. Position is relative to horizontal start of source block.
var size = this.getSize();
var fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2;
let size = this.getSize();
let fieldX = (this.sourceBlock_.RTL) ? -size.width / 2 : size.width / 2;
/** @type {!Element} */
this.textElement_ = Blockly.utils.createSvgElement('text',
this.textElement_ = Blockly.utils.dom.createSvgElement('text',
{
'class': (this as any).className_,
'x': fieldX,
@ -79,7 +79,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
},
this.fieldGroup_);
fieldX += 10; // size of first group.
this.textElement2_ = Blockly.utils.createSvgElement('text',
this.textElement2_ = <SVGTextElement>Blockly.utils.dom.createSvgElement('text',
{
'class': (this as any).className_,
'x': fieldX,
@ -89,17 +89,17 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
this.fieldGroup_);
this.updateEditable();
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
(this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot().appendChild(this.fieldGroup_);
// Force a render.
this.render_();
this.size_.width = 0;
this.isDirty_ = true;
(this as any).mouseDownWrapper_ =
Blockly.bindEventWithChecks_((this as any).getClickTarget_(), 'mousedown', this,
(this as any).onMouseDown_);
// Add second dropdown
if (this.shouldShowRect_()) {
this.box_ = Blockly.utils.createSvgElement('rect', {
this.box_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0,
@ -112,7 +112,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
'fill-opacity': 1
}, null);
this.fieldGroup_.insertBefore(this.box_, this.textElement_);
this.box2_ = Blockly.utils.createSvgElement('rect', {
this.box2_ = <SVGRectElement>Blockly.utils.dom.createSvgElement('rect', {
'rx': (Blockly.BlockSvg as any).CORNER_RADIUS,
'ry': (Blockly.BlockSvg as any).CORNER_RADIUS,
'x': 0,
@ -128,7 +128,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
}
// Force a reset of the text to add the arrow.
var text = this.text_;
let text = this.text_;
this.text_ = null;
this.setText(text);
}
@ -179,7 +179,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Not rendered yet.
return;
}
var text = this.text_;
let text = this.text_;
if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
@ -200,11 +200,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Prevent the field from disappearing if empty.
text = Blockly.Field.NBSP;
}
var textNode = document.createTextNode(text);
let textNode = document.createTextNode(text);
this.textElement2_.appendChild(textNode);
// Cached width is obsolete. Clear it.
this.size_.width = 0;
this.isDirty_ = true;
};
patchDualMotorText(text: string) {
@ -233,8 +233,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (this.textElement2_) {
this.textElement2_.parentNode.appendChild(this.arrow2_);
}
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.render();
if (this.sourceBlock_ && (<Blockly.BlockSvg>this.sourceBlock_).rendered) {
(<Blockly.BlockSvg>this.sourceBlock_).render();
this.sourceBlock_.bumpNeighbours_();
}
}
@ -244,7 +244,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
return 0;
}
var addedWidth = 0;
let addedWidth = 0;
if (this.sourceBlock_.RTL) {
(this as any).arrow2X_ = (this as any).arrowSize_ - (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING;
addedWidth = (this as any).arrowSize_ + (Blockly.BlockSvg as any).DROPDOWN_ARROW_PADDING;
@ -263,10 +263,10 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
return addedWidth;
};
updateWidth() {
updateSize_() {
// Calculate width of field
var width = Blockly.Field.getCachedWidth(this.textElement_);
var width2 = Blockly.Field.getCachedWidth(this.textElement2_);
let width = Blockly.Field.getCachedWidth(this.textElement_);
let width2 = Blockly.Field.getCachedWidth(this.textElement2_);
// Add padding to left and right of text.
if (this.EDITABLE) {
@ -311,15 +311,15 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// First dropdown
// Use one of the following options, medium motor, large motor or large motors (translated)
const textNode1 = document.createTextNode(this.getFirstValueI11n(this.value_));
const textNode1 = document.createTextNode(this.getFirstValueI11n(<string>this.value_));
this.textElement_.appendChild(textNode1);
// Second dropdown, no need to translate. Only port numbers
if (this.textElement2_) {
const textNode2 = document.createTextNode(this.getSecondValue(this.value_));
const textNode2 = document.createTextNode(this.getSecondValue(<string>this.value_));
this.textElement2_.appendChild(textNode2);
}
this.updateWidth();
this.updateSize_();
// Update text centering, based on newly calculated width.
let centerTextX = ((this as any).width1 - this.arrowWidth_) / 2;
@ -347,8 +347,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
}
// Apply new text element x position.
var width = Blockly.Field.getCachedWidth(this.textElement_);
var newX = centerTextX - width / 2;
let width = Blockly.Field.getCachedWidth(this.textElement_);
let newX = centerTextX - width / 2;
this.textElement_.setAttribute('x', `${newX}`);
// Update text centering, based on newly calculated width.
@ -377,8 +377,8 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
}
// Apply new text element x position.
var width2 = Blockly.Field.getCachedWidth(this.textElement2_);
var newX2 = centerTextX2 - width2 / 2;
let width2 = Blockly.Field.getCachedWidth(this.textElement2_);
let newX2 = centerTextX2 - width2 / 2;
this.textElement2_.setAttribute('x', `${newX2 + (this as any).width1 + Blockly.BlockSvg.BOX_FIELD_PADDING}`);
}
@ -401,7 +401,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (Blockly.DropDownDiv.hideIfOwner(this)) {
return;
}
this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * this.sourceBlock_.workspace.scale);
this.isFirst_ = e.clientX - this.getScaledBBox_().left < ((this as any).width1 * (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale);
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent();
@ -411,14 +411,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
// Accessibility properties
contentDiv.setAttribute('role', 'menu');
contentDiv.setAttribute('aria-haspopup', 'true');
let options = this.getOptions();
const foptions = this.getOptions(); // [img info, text]
let opts = {};
let conts = {};
let vals = {};
// Go through all option values and split them into groups
for (let opt = 0; opt < options.length; opt++) {
const value = options[opt][1];
for (let opt = 0; opt < foptions.length; opt++) {
const value = foptions[opt][1];
const motorValue = value.substring(value.indexOf('.') + 1);
const typeValue = motorValue.indexOf('large') == 0 ? 'large' : 'medium';
const portValue = motorValue.indexOf('large') == 0 ? motorValue.substring(5) : motorValue.substring(6);
@ -429,13 +429,14 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
if (!opts[key]) opts[key] = [];
opts[key].push(portValue);
conts[text] = options[opt][0];
conts[text] = foptions[opt][0];
vals[text] = value;
}
const currentFirst = this.getFirstValue(this.value_);
const currentSecond = this.getSecondValue(this.value_);
const currentFirst = this.getFirstValue(<string>this.value_);
//const currentSecond = this.getSecondValue(<string>this.value_);
let options: string[];
if (!this.isFirst_) {
options = opts[currentFirst];
} else {
@ -526,7 +527,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
Blockly.DropDownDiv.setColour(this.backgroundColour_, this.borderColour_);
// Calculate positioning based on the field position.
let scale = this.sourceBlock_.workspace.scale;
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale;
let width = this.isFirst_ ? (this as any).width1 : (this as any).width2;
let bBox = { width: this.size_.width, height: this.size_.height };
width *= scale;
@ -538,7 +539,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
@ -561,10 +562,11 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
* Callback for when the drop-down is hidden.
*/
protected onHide_() {
Blockly.DropDownDiv.content_.removeAttribute('role');
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
Blockly.DropDownDiv.getContentDiv().style.width = '';
const content = Blockly.DropDownDiv.getContentDiv();
content.removeAttribute('role');
content.removeAttribute('aria-haspopup');
content.removeAttribute('aria-activedescendant');
(content as HTMLElement).style.width = '';
if (this.isFirst_ && this.box_) {
this.box_.setAttribute('fill', this.sourceBlock_.getColour());
} else if (!this.isFirst_ && this.box2_) {

View File

@ -26,7 +26,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
this.width_ = parseInt(options.width) || 380;
this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateWidth = (Blockly.Field as any).prototype.updateWidth;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
if (!pxt.BrowserUtils.isIE() && !soundCache) {
@ -78,14 +78,14 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
contentDiv.style.width = (this as any).width_ + 'px';
contentDiv.style.cssFloat = 'left';
dropdownDiv.style.maxHeight = `410px`;
(dropdownDiv as HTMLElement).style.maxHeight = `410px`;
dropdownDiv.appendChild(categoriesDiv);
dropdownDiv.appendChild(contentDiv);
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
// Calculate positioning based on the field position.
let scale = this.sourceBlock_.workspace.scale;
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale;
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale;
bBox.height *= scale;
@ -95,7 +95,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
let secondaryX = primaryX;
let secondaryY = position.top;
// Set bounds to workspace; show the drop-down.
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
(Blockly.DropDownDiv as any).setBoundsElement((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
@ -236,7 +236,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
protected onHide_() {
super.onHide_();
Blockly.DropDownDiv.getContentDiv().style.maxHeight = '';
(Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = '';
this.stopSounds();
}

View File

@ -17,7 +17,7 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC
this.width_ = parseInt(options.width) || 300;
this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateWidth = (Blockly.Field as any).prototype.updateWidth;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
}

View File

@ -1,98 +0,0 @@
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
export interface FieldSpeedOptions extends Blockly.FieldCustomOptions {
min?: string;
max?: string;
label?: string;
}
export class FieldSpeed extends Blockly.FieldSlider implements Blockly.FieldCustom {
public isFieldCustom_ = true;
private params: any;
private speedSVG: SVGElement;
private circleBar: SVGCircleElement;
private reporter: SVGTextElement;
/**
* Class for a color wheel field.
* @param {number|string} value The initial content of the field.
* @param {Function=} opt_validator An optional function that is called
* to validate any constraints on what the user entered. Takes the new
* text as an argument and returns either the accepted text, a replacement
* text, or null to abort the change.
* @extends {Blockly.FieldNumber}
* @constructor
*/
constructor(value_: any, params: FieldSpeedOptions, opt_validator?: Function) {
super(String(value_), '-100', '100', null, '10', 'Speed', opt_validator);
this.params = params;
if (this.params['min']) this.min_ = parseFloat(this.params.min);
if (this.params['max']) this.max_ = parseFloat(this.params.max);
if (this.params['label']) this.labelText_ = this.params.label;
(this as any).sliderColor_ = '#a8aaa8';
}
createLabelDom_(labelText: string) {
var labelContainer = document.createElement('div');
this.speedSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement;
pxsim.svg.hydrate(this.speedSVG, {
viewBox: "0 0 200 100",
width: "170"
});
labelContainer.appendChild(this.speedSVG);
const outerCircle = pxsim.svg.child(this.speedSVG, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
'stroke': '#a8aaa8', 'stroke-width': '1rem'
}) as SVGCircleElement;
this.circleBar = pxsim.svg.child(this.speedSVG, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
'stroke': '#f12a21', 'stroke-width': '1rem'
}) as SVGCircleElement;
this.reporter = pxsim.svg.child(this.speedSVG, "text", {
'x': 100, 'y': 80,
'text-anchor': 'middle', 'dominant-baseline': 'middle',
'style': 'font-size: 50px',
'class': 'sim-text inverted number'
}) as SVGTextElement;
// labelContainer.setAttribute('class', 'blocklyFieldSliderLabel');
var readout = document.createElement('span');
readout.setAttribute('class', 'blocklyFieldSliderReadout');
// var label = document.createElement('span');
// label.setAttribute('class', 'blocklyFieldSliderLabelText');
// label.innerHTML = labelText;
// labelContainer.appendChild(label);
// labelContainer.appendChild(readout);
return [labelContainer, readout];
};
setReadout_(readout: Element, value: string) {
let x = parseFloat(value) || 0;
this.updateSpeed(x);
// Update reporter
this.reporter.textContent = `${x}%`;
}
private updateSpeed(speed: number) {
let sign = this.sign(speed);
speed = (Math.abs(speed) / 100 * 50) + 50;
if (sign == -1) speed = 50 - speed;
let c = Math.PI * (90 * 2);
let pct = ((100 - speed) / 100) * c;
this.circleBar.setAttribute('stroke-dashoffset', `${pct}`);
}
// A re-implementation of Math.sign (since IE11 doesn't support it)
private sign(num: number) {
return num ? num < 0 ? -1 : 1 : 0;
}
}

View File

@ -1,108 +0,0 @@
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
export interface FieldTurnRatioOptions extends Blockly.FieldCustomOptions {
}
export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.FieldCustom {
public isFieldCustom_ = true;
private params: any;
private path_: SVGPathElement;
private reporter_: SVGTextElement;
/**
* Class for a color wheel field.
* @param {number|string} value The initial content of the field.
* @param {Function=} opt_validator An optional function that is called
* to validate any constraints on what the user entered. Takes the new
* text as an argument and returns either the accepted text, a replacement
* text, or null to abort the change.
* @extends {Blockly.FieldNumber}
* @constructor
*/
constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) {
super(String(value_), '-200', '200', null, '10', 'TurnRatio', opt_validator);
this.params = params;
(this as any).sliderColor_ = '#a8aaa8';
}
static HALF = 80;
static HANDLE_RADIUS = 30;
static RADIUS = FieldTurnRatio.HALF - FieldTurnRatio.HANDLE_RADIUS - 1;
createLabelDom_(labelText: string) {
let labelContainer = document.createElement('div');
let svg = 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': (FieldTurnRatio.HALF + FieldTurnRatio.HANDLE_RADIUS + 10) + 'px',
'width': (FieldTurnRatio.HALF * 2) + 'px'
}, labelContainer);
let defs = Blockly.utils.createSvgElement('defs', {}, svg);
let marker = Blockly.utils.createSvgElement('marker', {
'id': 'head',
'orient': "auto",
'markerWidth': '2',
'markerHeight': '4',
'refX': '0.1', 'refY': '1.5'
}, defs);
let markerPath = Blockly.utils.createSvgElement('path', {
'd': 'M0,0 V3 L1.5,1.5 Z',
'fill': '#f12a21'
}, marker);
this.reporter_ = pxsim.svg.child(svg, "text", {
'x': FieldTurnRatio.HALF, 'y': 96,
'text-anchor': 'middle', 'dominant-baseline': 'middle',
'style': 'font-size: 50px',
'class': 'sim-text inverted number'
}) as SVGTextElement;
this.path_ = Blockly.utils.createSvgElement('path', {
'x1': FieldTurnRatio.HALF,
'y1': FieldTurnRatio.HALF,
'marker-end': 'url(#head)',
'style': 'fill: none; stroke: #f12a21; stroke-width: 10'
}, svg);
this.updateGraph_();
let readout = document.createElement('span');
readout.setAttribute('class', 'blocklyFieldSliderReadout');
return [labelContainer, readout];
};
updateGraph_() {
if (!this.path_) {
return;
}
let v = goog.math.clamp(parseFloat(this.getText()), -200, 200);
if (isNaN(v)) {
v = 0;
}
const x = v / 100;
const nx = Math.max(-1, Math.min(1, x));
const theta = Math.max(nx) * Math.PI / 2;
const r = FieldTurnRatio.RADIUS - 6;
let cx = FieldTurnRatio.HALF;
const cy = FieldTurnRatio.HALF - 22;
if (Math.abs(x) > 1) {
cx -= (x - (x > 0 ? 1 : -1)) * r / 2; // move center of circle
}
const alpha = 0.2 + Math.abs(nx) * 0.5;
const y1 = r * alpha;
const y2 = r * Math.sin(Math.PI / 2 - theta);
const x2 = r * Math.cos(Math.PI / 2 - theta);
const y3 = y2 - r * alpha * Math.cos(2 * theta);
const x3 = x2 - r * alpha * Math.sin(2 * theta);
const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`;
this.path_.setAttribute('d', d);
this.reporter_.textContent = `${v}`;
}
setReadout_(readout: Element, value: string) {
this.updateGraph_();
}
}