From 5e21f9ab6dd75bf9b74b139a4fa06d7f3317259f Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Sat, 6 Jan 2018 14:25:50 -0800 Subject: [PATCH 1/4] Add a speed field editor --- editor/extension.ts | 4 ++ editor/field_speed.ts | 92 ++++++++++++++++++++++++++++ libs/core/_locales/core-strings.json | 4 +- libs/core/ns.ts | 13 ++++ libs/core/output.ts | 6 +- 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 editor/field_speed.ts diff --git a/editor/extension.ts b/editor/extension.ts index 90055b3a..d2f8120b 100644 --- a/editor/extension.ts +++ b/editor/extension.ts @@ -4,6 +4,7 @@ import { deployCoreAsync, initAsync } from "./deploy"; import { FieldPorts } from "./field_ports"; import { FieldImages } from "./field_images"; +import {FieldSpeed} from "./field_speed"; pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { pxt.debug('loading pxt-ev3 target extensions...') @@ -15,6 +16,9 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P }, { selector: "images", editor: FieldImages + }, { + selector: "speed", + editor: FieldSpeed }], deployCoreAsync }; diff --git a/editor/field_speed.ts b/editor/field_speed.ts new file mode 100644 index 00000000..f77b166f --- /dev/null +++ b/editor/field_speed.ts @@ -0,0 +1,92 @@ +/// +/// + +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" + }); + + 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', 'alignment-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) { + this.updateSpeed(parseFloat(value)); + // Update reporter + this.reporter.textContent = `${value}`; + } + + private updateSpeed(speed: number) { + speed = Math.abs(speed); + speed = speed / 100 * 50; + speed += 50; + let c = Math.PI * (90 * 2); + let pct = ((100 - speed) / 100) * c; + this.circleBar.setAttribute('stroke-dashoffset', `${pct}`); + } + +} \ No newline at end of file diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index c705c3ef..d2482e3b 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -55,8 +55,8 @@ "motors.MotorBase.pauseUntilReady|block": "%motor|pause until ready", "motors.MotorBase.setBrake|block": "set %motor|brake %brake", "motors.MotorBase.setReversed|block": "set %motor|reversed %reversed", - "motors.MotorBase.setSpeedFor|block": "set %motor|speed to %speed|%|for %value|%unit", - "motors.MotorBase.setSpeed|block": "set %motor|speed to %speed|%", + "motors.MotorBase.setSpeedFor|block": "set %motor|speed to %speed=motorSpeedPicker|%|for %value|%unit", + "motors.MotorBase.setSpeed|block": "set %motor|speed to %speed=motorSpeedPicker|%", "motors.SynchedMotorPair.steerFor|block": "steer %chassis|turn ratio %turnRatio|speed %speed|%|for %value|%unit", "motors.SynchedMotorPair.steer|block": "steer %chassis|turn ratio %turnRatio|speed %speed|%", "motors.SynchedMotorPair.tankFor|block": "tank %motors|%speedLeft|%|%speedRight|%|for %value|%unit", diff --git a/libs/core/ns.ts b/libs/core/ns.ts index 8b137891..51ccea08 100644 --- a/libs/core/ns.ts +++ b/libs/core/ns.ts @@ -1 +1,14 @@ +namespace motors { + + /** + * A speed picker + * @param speed the speed + */ + //% blockId=motorSpeedPicker block="%speed" shim=TD_ID + //% speed.fieldEditor="speed" colorSecondary="#FFFFFF" + //% weight=0 blockHidden=1 + export function __speedPicker(speed: number): number { + return speed; + } +} \ No newline at end of file diff --git a/libs/core/output.ts b/libs/core/output.ts index 523a2dd3..3f8a4905 100644 --- a/libs/core/output.ts +++ b/libs/core/output.ts @@ -206,10 +206,9 @@ namespace motors { * Sets the speed of the motor. * @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50 */ - //% blockId=motorSetSpeed block="set %motor|speed to %speed|%" + //% blockId=motorSetSpeed block="set %motor|speed to %speed=motorSpeedPicker|%" //% on.fieldEditor=toggleonoff //% weight=99 blockGap=8 - //% speed.min=-100 speed.max=100 //% group="Motion" setSpeed(speed: number) { this.init(); @@ -226,9 +225,8 @@ namespace motors { * @param value the move quantity, eg: 2 * @param unit the meaning of the value */ - //% blockId=motorMove block="set %motor|speed to %speed|%|for %value|%unit" + //% blockId=motorMove block="set %motor|speed to %speed=motorSpeedPicker|%|for %value|%unit" //% weight=98 blockGap=8 - //% speed.min=-100 speed.max=100 //% group="Motion" setSpeedFor(speed: number, value: number, unit: MoveUnit) { this.init(); From 6a1b560101dbe7f5946cd88ee626bddb3c89ee5c Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Sat, 6 Jan 2018 14:40:09 -0800 Subject: [PATCH 2/4] Fix default --- libs/core/ns.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/ns.ts b/libs/core/ns.ts index 51ccea08..c27c4aa9 100644 --- a/libs/core/ns.ts +++ b/libs/core/ns.ts @@ -3,7 +3,7 @@ namespace motors { /** * A speed picker - * @param speed the speed + * @param speed the speed, eg: 50 */ //% blockId=motorSpeedPicker block="%speed" shim=TD_ID //% speed.fieldEditor="speed" colorSecondary="#FFFFFF" From a79704fecc10c27c069163e02ba25066fbd4faae Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Sat, 6 Jan 2018 17:16:08 -0800 Subject: [PATCH 3/4] Decompilation and minor PR feedback --- editor/field_speed.ts | 12 ++++++++---- libs/core/ns.ts | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/editor/field_speed.ts b/editor/field_speed.ts index f77b166f..ba4f3e94 100644 --- a/editor/field_speed.ts +++ b/editor/field_speed.ts @@ -77,16 +77,20 @@ export class FieldSpeed extends Blockly.FieldSlider implements Blockly.FieldCust setReadout_(readout: Element, value: string) { this.updateSpeed(parseFloat(value)); // Update reporter - this.reporter.textContent = `${value}`; + this.reporter.textContent = `${value}%`; } private updateSpeed(speed: number) { - speed = Math.abs(speed); - speed = speed / 100 * 50; - speed += 50; + 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; + } } \ No newline at end of file diff --git a/libs/core/ns.ts b/libs/core/ns.ts index c27c4aa9..9b083c78 100644 --- a/libs/core/ns.ts +++ b/libs/core/ns.ts @@ -7,7 +7,7 @@ namespace motors { */ //% blockId=motorSpeedPicker block="%speed" shim=TD_ID //% speed.fieldEditor="speed" colorSecondary="#FFFFFF" - //% weight=0 blockHidden=1 + //% weight=0 blockHidden=1 speed.fieldOptions.decompileLiterals=1 export function __speedPicker(speed: number): number { return speed; } From 64389a768985bda5f6d5cf9652cf52d516e0fd25 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Sun, 7 Jan 2018 10:06:02 -0800 Subject: [PATCH 4/4] more annotations --- libs/behaviors/_locales/behaviors-strings.json | 2 +- libs/behaviors/targetoverrides.ts | 2 +- libs/core/_locales/core-strings.json | 8 ++++---- libs/core/output.ts | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/behaviors/_locales/behaviors-strings.json b/libs/behaviors/_locales/behaviors-strings.json index 1862c5ea..7cd82798 100644 --- a/libs/behaviors/_locales/behaviors-strings.json +++ b/libs/behaviors/_locales/behaviors-strings.json @@ -1,7 +1,7 @@ { "behaviors.addBehavior|block": "add behavior %behavior", "behaviors.avoidCrash|block": "avoid crash using %ultrasonic", - "behaviors.driveForward|block": "drive %motors|forward at %speed|%", + "behaviors.driveForward|block": "drive %motors|forward at %speed=motorSpeedPicker|%", "behaviors|block": "behaviors", "{id:category}Behaviors": "Behaviors" } \ No newline at end of file diff --git a/libs/behaviors/targetoverrides.ts b/libs/behaviors/targetoverrides.ts index 99023221..4d64e6b9 100644 --- a/libs/behaviors/targetoverrides.ts +++ b/libs/behaviors/targetoverrides.ts @@ -49,7 +49,7 @@ namespace behaviors { * @param motors * @param speed the desired speed, eg: 50 */ - //% blockId=behaviorsDriveForward block="drive %motors|forward at %speed|%" + //% blockId=behaviorsDriveForward block="drive %motors|forward at %speed=motorSpeedPicker|%" export function driveForward(motors: motors.MotorBase, speed: number): behaviors.Behavior { return new DriveForwardBehavior(motors, speed); } diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index d2482e3b..f581aa99 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -57,10 +57,10 @@ "motors.MotorBase.setReversed|block": "set %motor|reversed %reversed", "motors.MotorBase.setSpeedFor|block": "set %motor|speed to %speed=motorSpeedPicker|%|for %value|%unit", "motors.MotorBase.setSpeed|block": "set %motor|speed to %speed=motorSpeedPicker|%", - "motors.SynchedMotorPair.steerFor|block": "steer %chassis|turn ratio %turnRatio|speed %speed|%|for %value|%unit", - "motors.SynchedMotorPair.steer|block": "steer %chassis|turn ratio %turnRatio|speed %speed|%", - "motors.SynchedMotorPair.tankFor|block": "tank %motors|%speedLeft|%|%speedRight|%|for %value|%unit", - "motors.SynchedMotorPair.tank|block": "tank %motors|%speedLeft|%|%speedRight|%", + "motors.SynchedMotorPair.steerFor|block": "steer %chassis|turn ratio %turnRatio|speed %speed=motorSpeedPicker|%|for %value|%unit", + "motors.SynchedMotorPair.steer|block": "steer %chassis|turn ratio %turnRatio|speed %speed=motorSpeedPicker|%", + "motors.SynchedMotorPair.tankFor|block": "tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%|for %value|%unit", + "motors.SynchedMotorPair.tank|block": "tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%", "motors.largeAB|block": "large A+B", "motors.largeAD|block": "large A+D", "motors.largeA|block": "large A", diff --git a/libs/core/output.ts b/libs/core/output.ts index 3f8a4905..2bd1f9c2 100644 --- a/libs/core/output.ts +++ b/libs/core/output.ts @@ -465,7 +465,7 @@ namespace motors { * @param speedLeft the speed on the left motor, eg: 50 * @param speedRight the speed on the right motor, eg: 50 */ - //% blockId=motorPairTank block="tank %motors|%speedLeft|%|%speedRight|%" + //% blockId=motorPairTank block="tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%" //% weight=20 blockGap=8 //% group="Sync Motion" tank(speedLeft: number, speedRight: number) { @@ -483,7 +483,7 @@ namespace motors { * @param value the amount of movement, eg: 2 * @param unit the unit of the value */ - //% blockId=motorPairTankFor block="tank %motors|%speedLeft|%|%speedRight|%|for %value|%unit" + //% blockId=motorPairTankFor block="tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%|for %value|%unit" //% weight=19 //% speedLeft.min=-100 speedLeft=100 //% speedRight.min=-100 speedRight=100 @@ -511,7 +511,7 @@ namespace motors { * @param value the move quantity, eg: 2 * @param unit the meaning of the value */ - //% blockId=motorPairSteer block="steer %chassis|turn ratio %turnRatio|speed %speed|%" + //% blockId=motorPairSteer block="steer %chassis|turn ratio %turnRatio|speed %speed=motorSpeedPicker|%" //% weight=7 blockGap=8 //% turnRatio.min=-200 turnRatio=200 //% inlineInputMode=inline @@ -527,7 +527,7 @@ namespace motors { * @param value the move quantity, eg: 2 * @param unit the meaning of the value */ - //% blockId=motorPairSteerFor block="steer %chassis|turn ratio %turnRatio|speed %speed|%|for %value|%unit" + //% blockId=motorPairSteerFor block="steer %chassis|turn ratio %turnRatio|speed %speed=motorSpeedPicker|%|for %value|%unit" //% weight=6 blockGap=8 //% turnRatio.min=-200 turnRatio=200 //% inlineInputMode=inline