From e24d4d56b1ab423f071ed77658fd2f45642a9e18 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Sat, 6 Jan 2018 00:12:32 -0800 Subject: [PATCH 1/6] More square shaped corners on blocks (toggle rect and arrow corner) --- theme/blockly.less | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/theme/blockly.less b/theme/blockly.less index 702f1cdb..0b13cadd 100644 --- a/theme/blockly.less +++ b/theme/blockly.less @@ -74,6 +74,15 @@ span.blocklyTreeLabel { border-radius: 0px !important; } +.blocklyDropDownArrow.arrowTop { + border-top-left-radius: 0px !important; +} + +.blocklyToggleRect { + rx: 0 !important; + ry: 0 !important; +} + /* Mobile */ @media only screen and (max-width: @largestMobileScreen) { #blocklyTrashIcon { From ed7099cc97bd5db60fee7014d53fac8e77d38dd5 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Sat, 6 Jan 2018 21:00:39 -0800 Subject: [PATCH 2/6] more square shaped corners --- theme/blockly.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/theme/blockly.less b/theme/blockly.less index 0b13cadd..71637b93 100644 --- a/theme/blockly.less +++ b/theme/blockly.less @@ -83,6 +83,10 @@ span.blocklyTreeLabel { ry: 0 !important; } +.blocklyDropDownButton { + border-radius: 0px !important; +} + /* Mobile */ @media only screen and (max-width: @largestMobileScreen) { #blocklyTrashIcon { From c70d6fe01a8b47dabd2221b0853913bbeab1eb42 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini <16690124+samelhusseini@users.noreply.github.com> Date: Sun, 7 Jan 2018 00:12:29 -0800 Subject: [PATCH 3/6] Remove unnecessary extra 'light' text in block pauseUntilLight (#203) --- libs/color-sensor/_locales/color-sensor-strings.json | 2 +- libs/color-sensor/color.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/color-sensor/_locales/color-sensor-strings.json b/libs/color-sensor/_locales/color-sensor-strings.json index b86a5904..bd243aa9 100644 --- a/libs/color-sensor/_locales/color-sensor-strings.json +++ b/libs/color-sensor/_locales/color-sensor-strings.json @@ -18,7 +18,7 @@ "sensors.ColorSensor.onColorDetected|block": "on %sensor|detected color %color", "sensors.ColorSensor.onLightChanged|block": "on %sensor|%mode|%condition", "sensors.ColorSensor.pauseForColor|block": "pause %sensor|for color %color", - "sensors.ColorSensor.pauseForLight|block": "pause %sensor|for %mode|light %condition", + "sensors.ColorSensor.pauseForLight|block": "pause %sensor|for %mode|%condition", "sensors.color1|block": "color 1", "sensors.color2|block": "color 2", "sensors.color3|block": "color 3", diff --git a/libs/color-sensor/color.ts b/libs/color-sensor/color.ts index ff06cf51..2346298b 100644 --- a/libs/color-sensor/color.ts +++ b/libs/color-sensor/color.ts @@ -182,7 +182,7 @@ namespace sensors { * @param color the color to detect */ //% help=sensors/color-sensor/pause-for-light - //% block="pause %sensor|for %mode|light %condition" + //% block="pause %sensor|for %mode|%condition" //% blockId=colorPauseForLight //% parts="colorsensor" //% blockNamespace=sensors From 7fe8580de879219227137be88fb18996534c2083 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini <16690124+samelhusseini@users.noreply.github.com> Date: Sun, 7 Jan 2018 07:52:07 -0800 Subject: [PATCH 4/6] Add brick buttons field editor (#202) * Add brick buttons field editor * add hover title text --- editor/extension.ts | 4 + editor/field_brickbuttons.ts | 159 +++++++++++++++++++++++++++++++++++ libs/core/buttons.ts | 4 + 3 files changed, 167 insertions(+) create mode 100644 editor/field_brickbuttons.ts diff --git a/editor/extension.ts b/editor/extension.ts index 90055b3a..877208c1 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 { FieldBrickButtons } from "./field_brickbuttons"; 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: "brickbuttons", + editor: FieldBrickButtons }], deployCoreAsync }; diff --git a/editor/field_brickbuttons.ts b/editor/field_brickbuttons.ts new file mode 100644 index 00000000..94f2bc2b --- /dev/null +++ b/editor/field_brickbuttons.ts @@ -0,0 +1,159 @@ +/// +/// + +export interface FieldPortsOptions extends Blockly.FieldCustomDropdownOptions { + columns?: string; + width?: string; +} + +export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.FieldCustom { + public isFieldCustom_ = true; + + // Width in pixels + private width_: number; + + // Columns in grid + private columns_: number; + + private savedPrimary_: string; + + constructor(text: string, options: FieldPortsOptions, validator?: Function) { + super(options.data); + + this.columns_ = parseInt(options.columns) || 4; + this.width_ = parseInt(options.width) || 150; + } + + /** + * Create a dropdown menu under the text. + * @private + */ + public showEditor_() { + // If there is an existing drop-down we own, this is a request to hide the drop-down. + if (Blockly.DropDownDiv.hideIfOwner(this)) { + return; + } + // If there is an existing drop-down someone else owns, hide it immediately and clear it. + Blockly.DropDownDiv.hideWithoutAnimation(); + Blockly.DropDownDiv.clearContent(); + // Populate the drop-down with the icons for this field. + let dropdownDiv = Blockly.DropDownDiv.getContentDiv(); + let contentDiv = document.createElement('div'); + // Accessibility properties + contentDiv.setAttribute('role', 'menu'); + contentDiv.setAttribute('aria-haspopup', 'true'); + + const buttonsSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement; + pxsim.svg.hydrate(buttonsSVG, { + viewBox: "0 0 256.68237 256.68237", + width: this.width_, + height: this.width_ + }); + contentDiv.appendChild(buttonsSVG); + + const gWrapper = pxsim.svg.child(buttonsSVG, 'g', { 'transform': 'translate(-4.695057,58.29823)' }); + const gInnerWrapper = pxsim.svg.child(gWrapper, 'g', { 'transform': 'translate(3.9780427e-6,-32.677281)' }); + + const back = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#6a6a6a;stroke-width:3.91719985', + d: 'M 106.30882,198.38022 C 84.431262,177.26258 50.453467,142.52878 50.453467,142.52878 v -7.12931 H 37.087971 a 32.381533,32.381533 0 1 1 0,-64.763062 H 50.457376 V 63.503186 L 105.71731,7.0563355 h 55.25604 c 25.02699,25.5048885 55.25994,55.2599395 55.25994,55.2599395 v 8.320133 h 12.77398 a 32.381533,32.381533 0 0 1 0,64.763062 h -12.77398 v 7.13323 c -29.43384,30.27603 -54.66454,55.85144 -54.66454,55.85144 z' + }) + + const buttonLeft = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#a8a9a8;stroke-width:3.91719985', + d: 'm 36.492567,78.357208 h 40.69971 V 126.48393 H 36.492567 A 24.063359,24.063359 0 0 1 12.429199,102.42057 v 0 A 24.063359,24.063359 0 0 1 36.492567,78.357208 Z' + }) + + const buttonRight = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#a8a9a8;stroke-width:3.91719985', + d: 'M 229.00727,126.48784 H 188.30756 V 78.361126 h 40.69971 a 24.063359,24.063359 0 0 1 24.06335,24.063354 v 0 a 24.063359,24.063359 0 0 1 -24.06335,24.06336 z' + }) + + const buttonEnter = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#3c3c3c;stroke-width:3.91719985', + d: 'm 109.27806,78.357208 h 46.9398 a 1.782326,1.782326 0 0 1 1.78233,1.782326 V 124.7016 a 1.782326,1.782326 0 0 1 -1.78233,1.78233 h -46.9398 a 1.782326,1.782326 0 0 1 -1.78233,-1.78233 V 80.139534 a 1.782326,1.782326 0 0 1 1.78233,-1.782326 z' + }) + + const buttonTop = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#a8a9a8;stroke-width:3.91719985', + d: 'm 108.09114,15.967966 49.90905,-0.59542 37.43276,38.619675 -15.44943,15.449437 V 97.367379 H 165.7249 V 81.306861 A 11.978797,11.978797 0 0 0 153.84012,69.422075 c -11.59883,-0.184102 -43.37516,0 -43.37516,0 A 9.6676495,9.6676495 0 0 0 100.36251,79.520618 V 97.347793 H 86.103905 V 69.422075 L 70.654464,53.97264 Z' + }) + + const buttonBottom = pxsim.svg.child(gInnerWrapper, 'path', { + style: 'fill:#a8a9a8;stroke-width:3.91719985', + d: 'M 157.78865,189.01028 108.18908,189.38233 70.654464,150.794 86.323259,135.4895 v -28.08625 h 14.101921 v 16.11144 a 12.006218,12.006218 0 0 0 11.85346,11.9788 c 11.59882,0.1841 43.13227,0 43.13227,0 a 10.18472,10.18472 0 0 0 10.38059,-10.38058 v -17.70966 h 14.39179 v 28.08632 l 15.3045,15.3045 z' + }) + + const buttons = [buttonEnter, buttonLeft, buttonRight, buttonTop, buttonBottom]; + const options = this.getOptions(); + for (let i = 0, option: any; option = options[i]; i++) { + let content = (options[i] as any)[0]; // Human-readable text or image. + const value = (options[i] as any)[1]; // Language-neutral value. + const button = buttons[i]; + button.setAttribute('id', ':' + i); // For aria-activedescendant + button.setAttribute('role', 'menuitem'); + button.setAttribute('cursor', 'pointer'); + const title = pxsim.svg.child(button, 'title'); + title.textContent = content; + + Blockly.bindEvent_(button, 'click', this, this.buttonClick_); + Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_); + // These are applied manually instead of using the :hover pseudoclass + // because Android has a bad long press "helper" menu and green highlight + // that we must prevent with ontouchstart preventDefault + Blockly.bindEvent_(button, 'mousedown', button, function (e) { + this.setAttribute('stroke', '#ffffff'); + e.preventDefault(); + }); + Blockly.bindEvent_(button, 'mouseover', button, function () { + this.setAttribute('stroke', '#ffffff'); + }); + Blockly.bindEvent_(button, 'mouseout', button, function () { + this.setAttribute('stroke', 'transparent'); + }); + + button.setAttribute('data-value', value); + } + + contentDiv.style.width = this.width_ + 'px'; + dropdownDiv.appendChild(contentDiv); + + 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 }; + 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; + // Set bounds to workspace; show the drop-down. + (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode); + (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, + this.onHide_.bind(this)); + } + + /** + * Callback for when a button is clicked inside the drop-down. + * Should be bound to the FieldIconMenu. + * @param {Event} e DOM event for the click/touch + * @private + */ + private buttonClick_ = function (e: any) { + let value = e.target.getAttribute('data-value'); + this.setValue(value); + Blockly.DropDownDiv.hide(); + }; + + /** + * 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'); + }; +} \ No newline at end of file diff --git a/libs/core/buttons.ts b/libs/core/buttons.ts index bd0b9292..45cca1b6 100644 --- a/libs/core/buttons.ts +++ b/libs/core/buttons.ts @@ -92,6 +92,7 @@ namespace brick { //% blockNamespace=brick //% weight=81 blockGap=8 //% group="Buttons" + //% button.fieldEditor="brickbuttons" isPressed() { return this._isPressed } @@ -107,6 +108,7 @@ namespace brick { //% blockNamespace=brick //% weight=80 //% group="Buttons" + //% button.fieldEditor="brickbuttons" wasPressed() { const r = this._wasPressed this._wasPressed = false @@ -125,6 +127,7 @@ namespace brick { //% blockNamespace=brick //% weight=99 blockGap=8 //% group="Buttons" + //% button.fieldEditor="brickbuttons" onEvent(ev: ButtonEvent, body: () => void) { control.onEvent(this._id, ev, body) } @@ -139,6 +142,7 @@ namespace brick { //% blockNamespace=brick //% weight=98 blockGap=8 //% group="Buttons" + //% button.fieldEditor="brickbuttons" pauseUntil(ev: ButtonEvent) { control.waitForEvent(this._id, ev); } From b3f9a4c92f54ee99297c711949e7eddc8190a1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Moskal?= Date: Sun, 7 Jan 2018 15:54:40 +0000 Subject: [PATCH 5/6] Make sure we stop motors on exit (#199) --- libs/core/linux.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/core/linux.cpp b/libs/core/linux.cpp index 5821d191..3b682e5c 100644 --- a/libs/core/linux.cpp +++ b/libs/core/linux.cpp @@ -483,7 +483,15 @@ void runLMS() { */ } +void stopMotors() { + uint8_t cmd[2] = { 0xA3, 0x0F }; + int fd = open("/dev/lms_pwm", O_RDWR); + write(fd, cmd, 2); + close(fd); +} + extern "C" void target_reset() { + stopMotors(); if (lmsPid) runLMS(); else From 7d01823caf7f21b0d14c811a3a6b0371e53f208d Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Sun, 7 Jan 2018 09:58:08 -0800 Subject: [PATCH 6/6] remove stopAllMotors on escape key --- libs/core/buttons.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/core/buttons.ts b/libs/core/buttons.ts index 45cca1b6..ab3e3854 100644 --- a/libs/core/buttons.ts +++ b/libs/core/buttons.ts @@ -170,7 +170,6 @@ namespace brick { // this needs to be done in query(), which is run without the main JS execution mutex // otherwise, while(true){} will lock the device if (ret & DAL.BUTTON_ID_ESCAPE) { - motors.stopAllMotors(); control.reset() } return ret