Compare commits

...

38 Commits

Author SHA1 Message Date
Dmitriy Antipov
6d222c50cb
Enable some features to improve the programming experience (#1022)
* Update pxtarget.json

Enable addNewTypeScriptFile so that you can split your code into multiple files. Enable blocksCollapsing to collapse blocks for convenience. Turn off highContrast it doesn't work now. We'll see later...

* enable-errorlist-option

* Update pxtarget.json

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-18 10:24:11 -07:00
Dmitriy Antipov
af263c8183
change-gray-ti-brown (#1021)
A typo that hadn't been noticed before. Does not affect the operation of the simulator.
2023-05-06 09:47:27 -07:00
Joey Wunderlich
dd18007035 1.4.32 2023-05-05 16:18:41 -07:00
Dmitriy Antipov
fba924d125
Add a none option to the simulator for the color sensor and colorEnumPicker extension (#1018)
* Update colorGrid.ts

* Update ns.ts

Added option to select emptiness (nothing) for the colorEnumPicker block.

* set-new-names-for-color-cells

Set new names for colored cells that pops up when hovering over an element. So the user will understand the color.

* Update sim/visuals/controls/colorGrid.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 16:04:13 -07:00
Dmitriy Antipov
76257775c3
Extended show screen blocks options (#1019)
* Update targetoverrides.ts

Convert old blocks to obsolete ones, new blocks differ in that you can specify the place to start printing along the horizontal axis of the screen (column). And also added a print style. These are the standard black text on a white background and the new white text on a black background. These two parameters are optionally expanded and optional, by default column = 1 and the print style is the same as before, black text on white.

* Update targetoverrides.ts

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update libs/screen/targetoverrides.ts

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 15:58:52 -07:00
Dmitriy Antipov
9be35a1034
Added support for Reflection Raw mode for the color sensor to the simulator (#1017)
* redesigned-code-to-support-ref-raw

Code that adds reflection raw support for the color sensor. The range of values for this is from 0 to 1023, because analog to digital converter is 10 bits. In fact, the color sensor gives values ​​of about 400 - 700, but I decided to leave the range, which could theoretically be. For other cases (reflections and ambient lighting), the range remains from 0 to 100. The average value when setting the mode in the simulator is displayed as 512, for other modes 50%.

* block-description-update

Block description update, as it did not take into account the mode of raw reflection values.
2023-05-05 15:54:56 -07:00
Dmitriy Antipov
2ca706df70
Fix music images items in other languages (#1014)
* correction-of-displaying-pictures-in-different languages

Correction of displaying pictures in different languages. The category options values were translated into different languages and the translated values could not be checked against the values from icon.jres.

* element-layout-fixes

Уlement layout fixes, for more readable blocks

* Update fieldeditors/field_music.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* Update fieldeditors/field_music.ts

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>

* tag-lang-tag-for-languages-other-than-en

The tag is not needed for English, because in the html tag it is already always set.

---------

Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
2023-05-05 15:50:04 -07:00
Dmitriy Antipov
dd415019c4
renderPorts-extra-checks-before-print (#1020)
When the program starts, when the showBoot() function is launched, the screenMode is checked and the showPorts function is launched, which in turn executes the renderPorts() function in a loop. While renderPorts is running, the screenMode may change, for example to ShowLines (when showString() was run). It may turn out that the mode has changed, and the renderPorts method has not been fully executed ... in the future, it will draw its own graphics on the screen, although we do not expect to see them already, because. a regime change has occurred. I added checks inside the function before displaying.
2023-05-05 15:46:43 -07:00
Joey Wunderlich
20581513b1 1.4.31 2023-04-29 17:22:20 -07:00
Dmitriy Antipov
1652fc5ffa
fix-bg-color (#1016) 2023-04-29 17:21:48 -07:00
Joey Wunderlich
8a1b6452bd
unpin beta (#1015) 2023-04-28 14:26:34 -07:00
Joey Wunderlich
a6712960db 1.4.30 2023-04-26 09:30:55 -07:00
Joey Wunderlich
bac70eb177 bump to pick up in ctx translations fix 2023-04-26 09:30:05 -07:00
Joey Wunderlich
830f5ffd77 1.4.29 2023-04-25 16:35:05 -07:00
Joey Wunderlich
aac5edd64b bump pxt to latest 7.2.* to pick up crowdin / build fixes 2023-04-25 16:25:21 -07:00
Joey Wunderlich
a54007d9ae 1.4.28 2023-04-25 14:56:21 -07:00
Joey Wunderlich
3952cb4858 1.4.27 2023-04-25 12:21:03 -07:00
Joey Wunderlich
0226888441
Change crowdin project to new name (kindscript->makecode) (#1013) 2023-04-25 12:20:42 -07:00
Joey Wunderlich
1373e9c0bc 1.4.26 2023-04-25 12:08:04 -07:00
Dmitriy Antipov
cabcb048e3
Troubleshooting updates v1.4.25 (#1012)
* sim_fix

ES version update

* fieldeditors-es-upgrade-to-es2017

Update es to fix issue with fieldeditors.

* editor-es-upgrade-to-es2017

Update es that fixes an issue with the editor.

* editor-download-dialog-fix

Solving a download error that arose due to problems with the buttons in the dialog box.

* return_field_motors

We return the fieldmotors field, because it is necessary about the choice of types of motors: medium, large, one or two.

* update-fields-for-motor-blocks

Set the blocks to the fieldmotors field. Change the name of the blocks for the motors.

* enable-debugger

Instead of the slowmo mode, which was before, a debugger was added, in which slowmo is present.

* fix-field-music

It turned out to update the fieldmusic menu. The menu is now displayed in the correct position.

* Update field_music.ts

* fix-field-brickbutton

Fixed issue with button select menu position from ev3 brick.

* Update dialogs.tsx

* Update field_motors.ts

Repartition of Label for fieldmotos, now it's more readable, it's better.

* motors-new-icon

Created new icons for motors for dropdown image.

* remove-ai-files-for-motors-icon

Remove ai image files for motors
2023-04-25 12:06:54 -07:00
microsoft-github-policy-service[bot]
512a441bca
Microsoft mandatory file (#1007)
Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com>
2022-08-30 10:35:02 -07:00
pelikhan
b4a18f260d lock beta to 1.4.24 2022-01-29 13:29:33 -08:00
pelikhan
6b3f2da72c 1.4.25 2022-01-29 12:05:31 -08:00
Dmitriy Antipov
b9b21328b1
return_blocks (#1003)
These blocks are present in the stable version, but not in the beta.
2021-11-29 09:57:33 -08:00
Richard Knoll
bef4ebac43
Updating npm dependencies and getting the build to work (#1001)
* Updating npm dependencies and getting the build to work

* update node in github actions to 14.x
2021-09-22 15:51:32 -07:00
pelikhan
617fdeb747 1.4.24 2021-09-10 11:21:42 -07:00
Dmitriy Antipov
c1aead1aa9
fix invert motor angle metod (#999) 2021-09-09 14:11:06 -07:00
Richard Knoll
bd0cf05693
Adding gh-actions workflows (#995)
* Adding gh-actions workflows

* Removing travis

* Handle tags also
2021-01-27 14:57:14 -08:00
Galen Nickel
faae7133f5
Word changes to reduce policheck hits (#992) 2020-11-06 13:09:53 -08:00
Peli de Halleux
5289850351 bump to v1.2.31 2020-10-02 23:42:38 +02:00
Peli de Halleux
ba6e2f7174 enable french 2020-10-02 23:13:04 +02:00
peli
7c5dfc474f update version to v1.2.30 2020-09-20 23:47:53 -07:00
peli
5ab3a6ae96 1.4.23 2020-09-10 23:40:51 -07:00
Maciej Mroziński
ed2e1f23e9
Change timeout 1s -> 5s to reduce Timeout errors (#988) 2020-09-11 08:25:12 +02:00
Maciej Mroziński
a157943bf7
Read default volume from device settings at start (#987) 2020-09-09 12:06:33 -07:00
peli
40aaf0fb18 1.4.22 2020-09-08 23:54:42 -07:00
Maciej Mroziński
b26cf289c3
Change sound volume to level (#986) 2020-09-08 23:53:33 -07:00
Peli de Halleux
f0821f8d6c cherry-pick Cooperate (#985)
* cooperate pause

* fix math

* update lastPause before pausing

* faster cooperation

Co-authored-by: Peli de Halleux <peli@DESKTOP-5B7QRAM.corp.microsoft.com>
2020-08-21 06:09:01 +02:00
58 changed files with 739 additions and 713 deletions

40
.github/workflows/pxt-buildmain.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: pxt-buildmain
on:
push:
branches:
- 'master'
- 'main'
create:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }}
NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

31
.github/workflows/pxt-buildpr.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: pxt-buildpr
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

39
.github/workflows/pxt-buildpush.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: pxt-buildpush
on:
push:
# main/master has its own build that includes the crowdin key
branches-ignore:
- 'main'
- 'master'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }}
NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

View File

@ -1,9 +0,0 @@
language: node_js
node_js:
- "8.9.0"
script:
- "node node_modules/pxt-core/built/pxt.js travis"
sudo: false
cache:
directories:
- node_modules

41
SECURITY.md Normal file
View File

@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@ -1,3 +1,3 @@
{
"appref": "v"
"appref": "v1.4"
}

View File

@ -27,7 +27,6 @@ while (true) {
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
}
pause(1);
}
```
@ -43,6 +42,5 @@ while (true) {
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
}
pause(1);
}
```

View File

@ -1,3 +1,3 @@
{
"appref": "v1.2.27"
"appref": "v1.2.31"
}

View File

@ -2,16 +2,16 @@
## Example #example
Use the a wait and the timer to generate a crazy number.
Use a wait and the timer to generate a number.
```blocks
let crazy = 0
let something = 0
for (let i = 0; i < 100; i++) {
control.waitMicros(100)
crazy = control.millis()
crazy += control.deviceSerialNumber()
if (crazy != 0) {
crazy = crazy / 1000000
something = control.millis()
something += control.deviceSerialNumber()
if (something != 0) {
something = something / 1000000
}
}
```

View File

@ -49,7 +49,7 @@ declare interface Serial extends EventTarget {
requestPort(options: SerialPortRequestOptions): Promise<SerialPort>;
}
class WebSerialPackageIO implements pxt.HF2.PacketIO {
class WebSerialPackageIO implements pxt.packetio.PacketIO {
onData: (v: Uint8Array) => void;
onError: (e: Error) => void;
onEvent: (v: Uint8Array) => void;
@ -87,7 +87,7 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
}
static portIos: WebSerialPackageIO[] = [];
static async mkPacketIOAsync(): Promise<pxt.HF2.PacketIO> {
static async mkPacketIOAsync(): Promise<pxt.packetio.PacketIO> {
const serial = (<any>navigator).serial;
if (serial) {
try {
@ -130,7 +130,7 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
private async closeAsync() {
// don't close port
return Promise.delay(500);
return pxt.U.delay(500);
}
reconnectAsync(): Promise<void> {
@ -146,11 +146,33 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO {
this._writer = this.port.writable.getWriter();
return this._writer.write(pkt);
}
onDeviceConnectionChanged(connect: boolean) {
throw new Error("onDeviceConnectionChanged not implemented");
}
onConnectionChanged() {
throw new Error("onConnectionChanged not implemented");
}
isConnecting() {
throw new Error("isConnecting not implemented");
return false;
}
isConnected() {
throw new Error("isConnected not implemented");
return false;
}
disposeAsync() {
return Promise.reject("disposeAsync not implemented")
}
}
function hf2Async() {
const pktIOAsync: Promise<pxt.HF2.PacketIO> = useWebSerial
? WebSerialPackageIO.mkPacketIOAsync() : pxt.HF2.mkPacketIOAsync()
const pktIOAsync: Promise<pxt.packetio.PacketIO> = useWebSerial
? WebSerialPackageIO.mkPacketIOAsync() : pxt.packetio.mkPacketIOAsync()
return pktIOAsync.then(h => {
let w = new Ev3Wrapper(h)
ev3 = w
@ -190,14 +212,19 @@ export function enableWebSerialAsync() {
else return Promise.resolve();
}
function cleanupAsync() {
async function cleanupAsync() {
if (ev3) {
console.log('cleanup previous port')
return ev3.disconnectAsync()
.catch(e => { })
.finally(() => { ev3 = undefined; });
try {
await ev3.disconnectAsync()
}
catch (e) {
}
finally {
ev3 = undefined;
}
}
return Promise.resolve();
}
let initPromise: Promise<Ev3Wrapper>
@ -207,7 +234,7 @@ function initHidAsync() { // needs to run within a click handler
if (useHID) {
initPromise = cleanupAsync()
.then(() => hf2Async())
.catch(err => {
.catch((err: any) => {
console.error(err);
initPromise = null
useHID = false;
@ -284,7 +311,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
.catch(e => {
// user easily forgets to stop robot
bluetoothTryAgainAsync().then(() => w.disconnectAsync())
.then(() => Promise.delay(1000))
.then(() => pxt.U.delay(1000))
.then(() => w.reconnectAsync());
// nothing we can do
@ -296,7 +323,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) {
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
.then(() => w.flashAsync(rbfPath, rbfBIN))
.then(() => w.runAsync(rbfPath))
.then(() => Promise.delay(500))
.then(() => pxt.U.delay(500))
.then(() => {
pxt.tickEvent("webserial.success");
return w.disconnectAsync()

View File

@ -1,4 +1,5 @@
import * as React from "react";
import { canUseWebSerial, enableWebSerialAsync } from "./deploy";
import { projectView } from "./extension";
@ -21,7 +22,7 @@ export function bluetoothTryAgainAsync(): Promise<void> {
function enableWebSerialAndCompileAsync() {
return enableWebSerialAsync()
.then(() => Promise.delay(500))
.then(() => pxt.U.delay(500))
.then(() => projectView.compile());
}
@ -52,11 +53,12 @@ function explainWebSerialPairingAsync(): Promise<void> {
export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (options: any) => Promise<number>): Promise<void> {
confirmAsync = _confirmAsync;
// https://msdn.microsoft.com/en-us/library/cc848897.aspx
// "For security reasons, data URIs are restricted to downloaded resources.
// "For security reasons, data URIs are restricted to downloaded resources.
// Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements"
const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge();
const docUrl = pxt.appTarget.appTheme.usbDocs;
const docUrl = (pxt.appTarget.appTheme.usbDocs ? pxt.appTarget.appTheme.usbDocs : false);
const jsx =
<div className="ui grid stackable">
@ -118,7 +120,7 @@ export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (o
hideAgree: false,
agreeLbl: lf("I got it"),
className: 'downloaddialog',
buttons: [canUseWebSerial() ? {
buttons: [canUseWebSerial() && {
label: lf("Bluetooth"),
icon: "bluetooth",
className: "bluetooth focused",
@ -126,20 +128,19 @@ export function showUploadDialogAsync(fn: string, url: string, _confirmAsync: (o
pxt.tickEvent("bluetooth.enable");
explainWebSerialPairingAsync()
.then(() => enableWebSerialAndCompileAsync())
.done();
}
} : undefined, downloadAgain ? {
}, downloadAgain && {
label: fn,
icon: "download",
className: "lightgrey focused",
url,
fileName: fn
} : undefined, docUrl ? {
}, docUrl && {
label: lf("Help"),
icon: "help",
className: "lightgrey",
url: docUrl
} : undefined]
}]
//timeout: 20000
}).then(() => { });
}

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,

View File

@ -26,7 +26,7 @@ export class Ev3Wrapper {
isStreaming = false;
dataDump = /talkdbg=1/.test(window.location.href);
constructor(public io: pxt.HF2.PacketIO) {
constructor(public io: pxt.packetio.PacketIO) {
io.onData = buf => {
buf = buf.slice(0, HF2.read16(buf, 0) + 2)
if (HF2.read16(buf, 4) == usbMagic) {
@ -81,7 +81,7 @@ export class Ev3Wrapper {
log(`stopping PXT app`)
let buf = this.allocCustom(2)
return this.justSendAsync(buf)
.then(() => Promise.delay(500))
.then(() => pxt.U.delay(500))
})
}
@ -116,7 +116,7 @@ export class Ev3Wrapper {
if (this.dataDump)
log("TALK: " + U.toHex(buf))
return this.io.sendPacketAsync(buf)
.then(() => this.msgs.shiftAsync(1000))
.then(() => this.msgs.shiftAsync(5000))
.then(resp => {
if (resp[2] != buf[2] || resp[3] != buf[3])
U.userError("msg count de-sync")
@ -236,7 +236,7 @@ export class Ev3Wrapper {
let contFileReq = this.allocSystem(1 + 2, 0x97)
HF2.write16(contFileReq, 7, 1000) // maxRead
contFileReq[6] = handle
return Promise.delay(data.length > 0 ? 0 : 500)
return pxt.U.delay(data.length > 0 ? 0 : 500)
.then(() => this.talkAsync(contFileReq, -1))
.then(resp)
}
@ -251,7 +251,7 @@ export class Ev3Wrapper {
let loop = (): Promise<void> =>
this.lock.enqueue("file", () =>
this.streamFileOnceAsync(path, cb))
.then(() => Promise.delay(500))
.then(() => pxt.U.delay(500))
.then(loop)
return loop()
}

View File

@ -120,20 +120,17 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
Blockly.DropDownDiv.setColour('#ffffff', '#dddddd');
// Calculate positioning based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale;
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale;
bBox.height *= scale;
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((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
// Position based on the field position.
Blockly.DropDownDiv.showPositionedByField(this, this.onHide_.bind(this));
// Update colour to look selected.
let source = this.sourceBlock_ as Blockly.BlockSvg;
this.savedPrimary_ = source?.getColour();
if (source?.isShadow()) {
source.setColour(source.getColourTertiary());
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
}
}
/**
@ -157,5 +154,12 @@ export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.
content.removeAttribute('aria-haspopup');
content.removeAttribute('aria-activedescendant');
(content as HTMLElement).style.width = '';
// Update color (deselect) on dropdown hide
let source = this.sourceBlock_ as Blockly.BlockSvg;
if (source?.isShadow()) {
source.setColour(this.savedPrimary_);
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', this.savedPrimary_);
}
};
}

View File

@ -5,10 +5,14 @@ export interface FieldColorEnumOptions extends pxtblockly.FieldColourNumberOptio
}
export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Blockly.FieldCustom {
public isFieldCustom_ = true;
private paramsData: any[];
constructor(text: string, params: FieldColorEnumOptions, opt_validator?: Function) {
super(text, params, opt_validator);
this.paramsData = params["data"];
}
mapColour(enumString: string) {
@ -33,11 +37,21 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
case 'ColorSensorColor.Red': return '#f12a21';
case 'ColorSensorColor.White': return '#ffffff';
case 'ColorSensorColor.Brown': return '#6c2d00';
case 'ColorSensorColor.None': return '#dfe6e9'; // Grey
case 'ColorSensorColor.None': return '#dfe6e9';
default: return colorString;
}
}
showEditor_() {
super.showEditor_();
const colorCells = document.querySelectorAll('.legoColorPicker td');
colorCells.forEach((cell) => {
const titleName = this.mapColour(cell.getAttribute("title"));
const index = this.paramsData.findIndex(item => item[1] === titleName);
cell.setAttribute("title", this.paramsData[index][0]);
});
}
/**
* Return the current colour.
* @param {boolean} opt_asHex optional field if the returned value should be a hex
@ -64,7 +78,7 @@ export class FieldColorEnum extends pxtblockly.FieldColorNumber implements Block
}
this.value_ = colour;
if (this.sourceBlock_) {
this.sourceBlock_.setColour(colour, colour, colour);
this.sourceBlock_.setColour(colour);
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,7 @@ declare const pxtTargetBundle: any;
let soundCache: any;
let soundIconCache: any;
let soundIconCacheArray: any;
export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldCustom {
public isFieldCustom_ = true;
@ -23,17 +24,17 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
super(text, { blocksInfo: options.blocksInfo, sort: true, data: options.data }, validator);
this.columns_ = parseInt(options.columns) || 4;
this.width_ = parseInt(options.width) || 380;
this.width_ = parseInt(options.width) || 450;
this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
if (!pxt.BrowserUtils.isIE() && !soundCache) {
soundCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['sounds.jres']);
}
if (!soundIconCache) {
soundIconCache = JSON.parse(pxtTargetBundle.bundledpkgs['music']['icons.jres']);
soundIconCacheArray = Object.entries(soundIconCache).filter(el => el[0] !== "*");
}
}
@ -50,14 +51,17 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
Blockly.DropDownDiv.hideWithoutAnimation();
Blockly.DropDownDiv.clearContent();
// Populate the drop-down with the icons for this field.
let dropdownDiv = Blockly.DropDownDiv.getContentDiv();
let dropdownDiv = Blockly.DropDownDiv.getContentDiv() as HTMLElement;
let contentDiv = document.createElement('div');
// Accessibility properties
contentDiv.setAttribute('role', 'menu');
contentDiv.setAttribute('aria-haspopup', 'true');
contentDiv.className = 'blocklyMusicFieldOptions';
contentDiv.style.display = "flex";
contentDiv.style.flexWrap = "wrap";
contentDiv.style.float = "none";
const options = this.getOptions();
options.sort();
//options.sort(); // Do not need to use to not apply sorting in different languages
// Create categoies
const categories = this.getCategories(options);
@ -68,7 +72,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
// Accessibility properties
categoriesDiv.setAttribute('role', 'menu');
categoriesDiv.setAttribute('aria-haspopup', 'true');
categoriesDiv.style.backgroundColor = this.sourceBlock_.getColourTertiary();
categoriesDiv.style.backgroundColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
categoriesDiv.className = 'blocklyMusicFieldCategories';
this.refreshCategories(categoriesDiv, categories);
@ -82,30 +86,18 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
dropdownDiv.appendChild(categoriesDiv);
dropdownDiv.appendChild(contentDiv);
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
// Calculate positioning based on the field position.
let scale = (<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).scale;
let bBox = { width: this.size_.width, height: this.size_.height };
bBox.width *= scale;
bBox.height *= scale;
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((<Blockly.WorkspaceSvg>this.sourceBlock_.workspace).getParentSvg().parentNode);
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
this.onHide_.bind(this));
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
// Position based on the field position.
Blockly.DropDownDiv.showPositionedByField(this, this.onHide_.bind(this));
// Update colour to look selected.
if (this.sourceBlock_.isShadow()) {
this.savedPrimary_ = this.sourceBlock_.getColour();
this.sourceBlock_.setColour(this.sourceBlock_.getColourTertiary(),
this.sourceBlock_.getColourSecondary(), this.sourceBlock_.getColourTertiary());
} else if (this.box_) {
this.box_.setAttribute('fill', this.sourceBlock_.getColourTertiary());
let source = this.sourceBlock_ as Blockly.BlockSvg;
this.savedPrimary_ = source?.getColour();
if (source?.isShadow()) {
source.setColour(source.getColourTertiary());
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary());
}
}
@ -122,7 +114,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
}
refreshCategories(categoriesDiv: Element, categories: string[]) {
// Show category dropdown.
// Show category dropdown.
for (let i = 0; i < categories.length; i++) {
const category = categories[i];
@ -138,6 +130,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
backgroundColor = '#0c4e5e';
button.setAttribute('aria-selected', 'true');
}
button.style.padding = "2px 6px";
button.style.backgroundColor = backgroundColor;
button.style.borderColor = backgroundColor;
Blockly.bindEvent_(button, 'click', this, this.categoryClick_);
@ -151,7 +144,7 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
}
refreshOptions(contentDiv: Element, options: any) {
const categories = this.getCategories(options);
// Show options
for (let i = 0, option: any; option = options[i]; i++) {
let content = (options[i] as any)[0]; // Human-readable text or image.
@ -186,11 +179,11 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
let backgroundColor = this.savedPrimary_ || this.sourceBlock_.getColour();
if (value == this.getValue()) {
// This icon is selected, show it in a different colour
backgroundColor = this.sourceBlock_.getColourTertiary();
backgroundColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
button.setAttribute('aria-selected', 'true');
}
button.style.backgroundColor = backgroundColor;
button.style.borderColor = this.sourceBlock_.getColourTertiary();
button.style.borderColor = (this.sourceBlock_ as Blockly.BlockSvg).getColourTertiary();
Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
// These are applied manually instead of using the :hover pseudoclass
@ -215,15 +208,27 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
this.setAttribute('class', 'blocklyDropDownButton');
contentDiv.removeAttribute('aria-activedescendant');
});
// Find index in array by category name
const categoryIndex = categories.indexOf(category);
let buttonImg = document.createElement('img');
buttonImg.src = this.getSoundIcon(category);
//buttonImg.alt = icon.alt;
buttonImg.src = this.getSoundIcon(categoryIndex);
// Upon click/touch, we will be able to get the clicked element as e.target
// Store a data attribute on all possible click targets so we can match it to the icon.
const textNode = this.createTextNode_(content);
button.setAttribute('data-value', value);
buttonImg.setAttribute('data-value', value);
buttonImg.style.height = "auto";
textNode.setAttribute('data-value', value);
if (pxt.Util.userLanguage() !== "en") textNode.setAttribute('lang', pxt.Util.userLanguage()); // for hyphens, here you need to set the correct abbreviation of the selected language
textNode.style.display = "block";
textNode.style.lineHeight = "1rem";
textNode.style.marginBottom = "5%";
textNode.style.padding = "0px 8px";
textNode.style.wordBreak = "break-word";
textNode.style.hyphens = "auto";
button.appendChild(buttonImg);
button.appendChild(textNode);
@ -238,12 +243,19 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
super.onHide_();
(Blockly.DropDownDiv.getContentDiv() as HTMLElement).style.maxHeight = '';
this.stopSounds();
// Update color (deselect) on dropdown hide
let source = this.sourceBlock_ as Blockly.BlockSvg;
if (source?.isShadow()) {
source.setColour(this.savedPrimary_);
} else if (this.borderRect_) {
this.borderRect_.setAttribute('fill', this.savedPrimary_);
}
}
protected createTextNode_(content: string) {
const category = this.parseCategory(content);
let text = content.substr(content.indexOf(' ') + 1);
text = text.length > 15 ? text.substr(0, 12) + "..." : text;
const textSpan = document.createElement('span');
textSpan.setAttribute('class', 'blocklyDropdownText');
textSpan.textContent = text;
@ -311,9 +323,9 @@ export class FieldMusic extends pxtblockly.FieldImages implements Blockly.FieldC
pxsim.AudioContextManager.stop();
}
private getSoundIcon(category: string) {
if (soundIconCache && soundIconCache[category]) {
return soundIconCache[category].icon;
private getSoundIcon(indexCategory: number) {
if (soundIconCacheArray && soundIconCacheArray[indexCategory]) {
return soundIconCacheArray[indexCategory][1].icon;
}
return undefined;
}

View File

@ -18,7 +18,6 @@ export class FieldPorts extends pxtblockly.FieldImages implements Blockly.FieldC
this.setText = Blockly.FieldDropdown.prototype.setText;
this.updateSize_ = (Blockly.Field as any).prototype.updateSize_;
this.updateTextNode_ = Blockly.Field.prototype.updateTextNode_;
}
trimOptions_() {

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"noImplicitAny": false,
"noImplicitReturns": true,
"module": "commonjs",

12
libs/base/shims.d.ts vendored
View File

@ -87,6 +87,12 @@ declare interface Buffer {
*/
//% shim=BufferMethods::write
write(dstOffset: int32, src: Buffer): void;
/**
* Compute k-bit FNV-1 non-cryptographic hash of the buffer.
*/
//% shim=BufferMethods::hash
hash(bits: int32): uint32;
}
declare namespace control {
@ -94,14 +100,14 @@ declare namespace control {
* Create a new zero-initialized buffer.
* @param size number of bytes in the buffer
*/
//% shim=control::createBuffer
//% deprecated=1 shim=control::createBuffer
function createBuffer(size: int32): Buffer;
/**
* Create a new buffer with UTF8-encoded string
* @param str the string to put in the buffer
*/
//% shim=control::createBufferFromUTF8
//% deprecated=1 shim=control::createBufferFromUTF8
function createBufferFromUTF8(str: string): Buffer;
}
declare namespace loops {
@ -198,6 +204,8 @@ declare namespace control {
*/
//% shim=control::dmesgValue
function dmesgValue(v: any): void;
}
declare namespace control {
/**
* Force GC and dump basic information about heap.

View File

@ -250,7 +250,7 @@ namespace sensors {
}
/**
* Measure the ambient or reflected light value from 0 (darkest) to 100 (brightest).
* Measure the ambient or reflected light value from 0 (darkest) to 100 (brightest). In raw reflection light mode, the range will be different.
* @param sensor the color sensor port
*/
//% help=sensors/color-sensor/light

View File

@ -1,5 +1,3 @@
namespace sensors {
/**
@ -9,9 +7,9 @@ namespace sensors {
//% blockId=colorEnumPicker block="%color" shim=TD_ID
//% weight=0 blockHidden=1 turnRatio.fieldOptions.decompileLiterals=1
//% color.fieldEditor="colorenum"
//% color.fieldOptions.colours='["#f12a21", "#ffd01b", "#006db3", "#00934b", "#000000", "#6c2d00", "#ffffff"]'
//% color.fieldOptions.colours='["#f12a21", "#ffd01b", "#006db3", "#00934b", "#000000", "#6c2d00", "#ffffff", "#dfe6e9"]'
//% color.fieldOptions.columns=2 color.fieldOptions.className='legoColorPicker'
export function __colorEnumPicker(color: ColorSensorColor): number {
return color;
}
}
}

11
libs/core/cooperate.ts Normal file
View File

@ -0,0 +1,11 @@
namespace control {
let lastPause = 0;
const COOPERATION_INTERVAL = 20
export function cooperate() {
const now = control.millis()
if (now - lastPause > COOPERATION_INTERVAL) {
lastPause = now
pause(1)
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -21,8 +21,7 @@ namespace sensors.internal {
const now = control.millis();
if (now - this.lastQuery >= this.interval * 2)
this.queryAndUpdate(); // sensor poller is not allowed to run
if (now - this.lastPause >= this.interval * 5)
pause(1); // allow events to trigger
control.cooperate(); // allow events to trigger
}
private queryAndUpdate() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -124,7 +124,7 @@ namespace motors {
export function stopAll() {
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
writePWM(b);
pause(1);
control.cooperate();
}
/**
@ -136,7 +136,7 @@ namespace motors {
//% help=motors/reset-all
export function resetAll() {
reset(Output.ALL)
pause(1);
control.cooperate();
}
interface MoveSchedule {
@ -196,6 +196,7 @@ namespace motors {
*/
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=60 blockGap=8
//% group="Properties"
//% help=motors/motor/set-brake
@ -210,6 +211,7 @@ namespace motors {
*/
//% blockId=outputMotorSetPauseMode block="set %motor|pause on run %brake=toggleOnOff"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=60 blockGap=8
//% group="Properties"
setPauseOnRun(value: boolean) {
@ -217,11 +219,12 @@ namespace motors {
this._pauseOnRun = value;
}
/**
/**
* Inverts the motor polarity
*/
//% blockId=motorSetInverted block="set %motor|inverted %reversed=toggleOnOff"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=59 blockGap=8
//% group="Properties"
//% help=motors/motor/set-inverted
@ -234,11 +237,12 @@ namespace motors {
return this._inverted ? -1 : 1;
}
/**
/**
* Set the settle time after braking in milliseconds (default is 10ms).
*/
//% blockId=motorSetBrakeSettleTime block="set %motor|brake settle time %millis|ms"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=1 blockGap=8
//% group="Properties"
//% millis.defl=200 millis.min=0 millis.max=500
@ -269,7 +273,7 @@ namespace motors {
if (this._brake && this._brakeSettleTime > 0)
pause(this._brakeSettleTime);
else {
pause(1);
control.cooperate();
}
}
@ -280,7 +284,7 @@ namespace motors {
// allow robot to settle
this.settle();
} else {
pause(1);
control.cooperate();
}
}
@ -344,6 +348,7 @@ namespace motors {
//% weight=100 blockGap=8
//% group="Move"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% expandableArgumentMode=toggle
//% help=motors/motor/run
run(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
@ -357,7 +362,7 @@ namespace motors {
// special: 0 is infinity
if (schedule.steps[0] + schedule.steps[1] + schedule.steps[2] == 0) {
this._run(schedule.speed);
pause(1);
control.cooperate();
return;
}
@ -393,6 +398,7 @@ namespace motors {
//% weight=99 blockGap=8
//% group="Move"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% help=motors/motor/ramp
//% inlineInputMode=inline
//% expandableArgumentMode=toggle
@ -422,6 +428,7 @@ namespace motors {
*/
//% blockId=outputMotorsetRunRamp block="set %motor|run %ramp to $value||$unit"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=21 blockGap=8
//% group="Properties"
//% help=motors/motor/set-run-phase
@ -493,6 +500,7 @@ namespace motors {
*/
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=58 blockGap=8
//% group="Properties"
//% help=motors/motor/set-regulated
@ -518,6 +526,7 @@ namespace motors {
*/
//% blockId=motorPauseUntilRead block="pause until %motor|ready"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=90 blockGap=8
//% group="Move"
pauseUntilReady(timeOut?: number) {
@ -576,7 +585,8 @@ namespace motors {
*/
//% blockId=motorSpeed block="%motor|speed"
//% motor.fieldEditor="motors"
//% weight=72
//% motor.fieldOptions.decompileLiterals=1
//% weight=72
//% blockGap=8
//% group="Counters"
//% help=motors/motor/speed
@ -591,13 +601,14 @@ namespace motors {
*/
//% blockId=motorAngle block="%motor|angle"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=70
//% blockGap=8
//% group="Counters"
//% help=motors/motor/angle
angle(): number {
this.init();
return getMotorData(this._port).count;
return getMotorData(this._port).count * this.invertedFactor();
}
/**
@ -605,6 +616,7 @@ namespace motors {
*/
//% blockId=motorClearCount block="clear %motor|counters"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=68
//% blockGap=8
//% group="Counters"
@ -633,6 +645,7 @@ namespace motors {
*/
//% blockId=motorPauseUntilStall block="pause until %motor|stalled"
//% motor.fieldEditor="motors"
//% motor.fieldOptions.decompileLiterals=1
//% weight=89
//% group="Move"
//% help=motors/motor/pause-until-stalled
@ -656,28 +669,28 @@ namespace motors {
}
}
//% whenUsed fixedInstance block="large motor A" jres=icons.portA
//% whenUsed fixedInstance block="large motor A" jres=icons.motorLargePortA
export const largeA = new Motor(Output.A, true);
//% whenUsed fixedInstance block="large motor B" jres=icons.portB
//% whenUsed fixedInstance block="large motor B" jres=icons.motorLargePortB
export const largeB = new Motor(Output.B, true);
//% whenUsed fixedInstance block="large motor C" jres=icons.portC
//% whenUsed fixedInstance block="large motor C" jres=icons.motorLargePortC
export const largeC = new Motor(Output.C, true);
//% whenUsed fixedInstance block="large motor D" jres=icons.portD
//% whenUsed fixedInstance block="large motor D" jres=icons.motorLargePortD
export const largeD = new Motor(Output.D, true);
//% whenUsed fixedInstance block="medium motor A" jres=icons.portA
//% whenUsed fixedInstance block="medium motor A" jres=icons.motorMeduimPortA
export const mediumA = new Motor(Output.A, false);
//% whenUsed fixedInstance block="medium motor B" jres=icons.portB
//% whenUsed fixedInstance block="medium motor B" jres=icons.motorMeduimPortB
export const mediumB = new Motor(Output.B, false);
//% whenUsed fixedInstance block="medium motor C" jres=icons.portC
//% whenUsed fixedInstance block="medium motor C" jres=icons.motorMeduimPortC
export const mediumC = new Motor(Output.C, false);
//% whenUsed fixedInstance block="medium motor D" jres=icons.portD
//% whenUsed fixedInstance block="medium motor D" jres=icons.motorMeduimPortD
export const mediumD = new Motor(Output.D, false);
//% fixedInstances
@ -697,10 +710,10 @@ namespace motors {
}
/**
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
* Use the Move Tank block for robot vehicles that have two Large Motors,
* with one motor driving the left side of the vehicle and the other the right side.
* You can make the two motors go at different speeds or in different directions
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
* Use the Move Tank block for robot vehicles that have two Large Motors,
* with one motor driving the left side of the vehicle and the other the right side.
* You can make the two motors go at different speeds or in different directions
* to make your robot turn.
* @param speedLeft the speed on the left motor, eg: 50
* @param speedRight the speed on the right motor, eg: 50
@ -708,7 +721,7 @@ namespace motors {
* @param unit (optional) unit of the value
*/
//% blockId=motorPairTank block="tank **motors** %motors %speedLeft=motorSpeedPicker|\\% %speedRight=motorSpeedPicker|\\%||for %value %unit"
//% motors.fieldEditor="ports"
//% motors.fieldEditor="motors"
//% weight=96 blockGap=8
//% inlineInputMode=inline
//% group="Move"
@ -738,7 +751,7 @@ namespace motors {
* @param unit (optional) unit of the value
*/
//% blockId=motorPairSteer block="steer **motors** %chassis turn ratio %turnRatio=motorTurnRatioPicker speed %speed=motorSpeedPicker|\\%||for %value %unit"
//% chassis.fieldEditor="ports"
//% chassis.fieldEditor="motors"
//% weight=95
//% turnRatio.min=-200 turnRatio=200
//% inlineInputMode=inline
@ -811,16 +824,16 @@ namespace motors {
}
}
//% whenUsed fixedInstance block="B+C" jres=icons.portBC
//% whenUsed fixedInstance block="large motors B+C" jres=icons.dualMotorLargePortBC
export const largeBC = new SynchedMotorPair(Output.BC);
//% whenUsed fixedInstance block="A+D" jres=icons.portAD
//% whenUsed fixedInstance block="large motors A+D" jres=icons.dualMotorLargePortAD
export const largeAD = new SynchedMotorPair(Output.AD);
//% whenUsed fixedInstance block="A+B" jres=icons.portAB
//% whenUsed fixedInstance block="large motors A+B" jres=icons.dualMotorLargePortAB
export const largeAB = new SynchedMotorPair(Output.AB);
//% whenUsed fixedInstance block="C+D" jres=icons.portCD
//% whenUsed fixedInstance block="large motors C+D" jres=icons.dualMotorLargePortCD
export const largeCD = new SynchedMotorPair(Output.CD);
function reset(out: Output) {

View File

@ -28,7 +28,8 @@
"platform.h",
"platform.cpp",
"dmesg.cpp",
"integrator.ts"
"integrator.ts",
"cooperate.ts"
],
"testFiles": [
"test.ts"

View File

@ -12,4 +12,5 @@ music.setTempo(120)
music.noteFrequency(Note.C)
music.beat()
music.setVolume(50)
```
music.volume()
```

View File

@ -13,7 +13,22 @@
namespace music {
uint8_t currVolume = 50;
int _readSystemVolume() {
char ParBuf[8];
int volume;
int fd = open("../sys/settings/Volume.rtf", O_RDONLY);
read(fd, ParBuf, sizeof(ParBuf));
close(fd);
if (sscanf(ParBuf,"%d",&volume) > 0) {
if ((volume >= 0) && (volume <= 100)) {
return volume;
}
}
return 50;
}
uint8_t currVolume = _readSystemVolume();
uint8_t *lmsSoundMMap;
int writeDev(void *data, int size) {
@ -37,6 +52,18 @@ void setVolume(int volume) {
currVolume = max(0, min(100, volume));
}
/**
* Return the output volume of the sound synthesizer.
*/
//% weight=96
//% blockId=synth_get_volume block="volume"
//% parts="speaker" blockGap=8
//% help=music/volume
//% weight=1
int volume() {
return currVolume;
}
#define SOUND_CMD_BREAK 0
#define SOUND_CMD_TONE 1
#define SOUND_CMD_PLAY 2
@ -45,7 +72,7 @@ void setVolume(int volume) {
struct ToneCmd {
uint8_t cmd;
uint8_t vol;
uint8_t lvl;
uint16_t freq;
uint16_t duration;
};
@ -55,10 +82,26 @@ static void _stopSound() {
writeDev(&cmd, sizeof(cmd));
}
static uint8_t _getVolumeLevel(uint8_t volume, uint8_t levels) {
uint8_t level;
uint8_t step = (uint8_t) (100 / (levels - 1));
if (volume < step) {
level = 0;
} else if (volume > step * (levels - 1)) {
level = levels;
} else {
level = (uint8_t) (volume / step);
}
return level;
}
static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume) {
// https://github.com/mindboards/ev3sources/blob/78ebaf5b6f8fe31cc17aa5dce0f8e4916a4fc072/lms2012/c_sound/source/c_sound.c#L471
uint8_t level = _getVolumeLevel(volume, 13);
ToneCmd cmd;
cmd.cmd = SOUND_CMD_TONE;
cmd.vol = volume;
cmd.lvl = level;
cmd.freq = frequency;
cmd.duration = duration;
// (*SoundInstance.pSound).Busy = TRUE;
@ -122,7 +165,8 @@ void playSample(Buffer buf) {
stopUser();
pthread_mutex_lock(&pumpMutex);
*lmsSoundMMap = 1; // BUSY
uint8_t cmd[] = {SOUND_CMD_PLAY, (uint8_t)((currVolume / 33) + 1)};
// https://github.com/mindboards/ev3sources/blob/78ebaf5b6f8fe31cc17aa5dce0f8e4916a4fc072/lms2012/c_sound/source/c_sound.c#L605
uint8_t cmd[] = {SOUND_CMD_PLAY, _getVolumeLevel(currVolume, 8)};
writeDev(cmd, 2);
decrRC(currentSample);
currentSample = buf;
@ -201,4 +245,4 @@ Buffer buffer(Sound snd) {
void play(Sound snd) {
music::playSample(snd);
}
}
}

10
libs/music/shims.d.ts vendored
View File

@ -13,6 +13,16 @@ declare namespace music {
//% weight=1 shim=music::setVolume
function setVolume(volume: int32): void;
/**
* Return the output volume of the sound synthesizer.
*/
//% weight=96
//% blockId=synth_get_volume block="volume"
//% parts="speaker" blockGap=8
//% help=music/volume
//% weight=1 shim=music::volume
function volume(): int32;
/**
* Play a tone through the speaker for some amount of time.
* @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C

View File

@ -5,3 +5,4 @@ music.playTone(1440, 500)
pause(500)
music.playTone(2440, 500)
pause(500)
music.volume()

View File

@ -22,6 +22,7 @@ namespace _screen_internal {
namespace brick {
const textOffset = 4;
const lineOffset = 2;
enum ScreenMode {
None,
ShowLines,
@ -29,6 +30,14 @@ namespace brick {
Ports,
Custom
}
export enum PrintStyle {
//% block="black on white"
BlackOnWhite,
//% block="white on black"
WhiteOnBlack
}
let screenMode = ScreenMode.None;
export let font = image.font8;
@ -48,6 +57,48 @@ namespace brick {
return ((screen.height - textOffset) / lineHeight()) >> 0
}
/**
* Number of columns
*/
//%
export function columnCount(): number {
return ((screen.width - textOffset) / font.charWidth) >> 0
}
/**
* Show text on the screen on a specific line and starting at a column and the selected print style.
* @param text the text to print on the screen, eg: "Hello world"
* @param line the line number to print the text at (starting at 1), eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintString block="show string $text|at line $line||column $column|style $printStyle"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-string
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printString(text: string, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines;
screen.fill(0);
}
line = (line - 1) >> 0; // line indexing starts at 1
column = (column - 1) >> 0; // column indexing starts at 1
const nlines = lineCount();
const nColumn = columnCount();
if (line < 0 || line > nlines) return; // out of screen by line
if (column < 0 || column > nColumn) return; // out of screen by column
const w = font.charWidth;
const h = lineHeight();
const x = textOffset + w * column;
const y = textOffset + h * line;
screen.fillRect(x, y, text.length * font.charWidth, h, (printStyle == PrintStyle.BlackOnWhite ? 0 : 255)); // clear background
screen.print(text, x, y, (printStyle == PrintStyle.BlackOnWhite ? 1 : 2), font);
}
/**
* Show text on the screen at a specific line.
* @param text the text to print on the screen, eg: "Hello world"
@ -56,7 +107,8 @@ namespace brick {
//% blockId=screen_print block="show string %text|at line %line"
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-string
//% line.min=1 line.max=10
//% line.min=1 line.max=12
//% deprecated=true
export function showString(text: string, line: number) {
if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines;
@ -74,19 +126,56 @@ namespace brick {
screen.print(text, textOffset, y, 1, font);
}
/**
* Show a number on the screen on a specific line and starting at a column and the selected print style.
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintNumber block="show number $value|at line $line||column $column|style $printStyle"
//% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-number
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printNumber(value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
printString("" + value, line, column, printStyle);
}
/**
* Show a number on the screen
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
*/
//% blockId=screenShowNumber block="show number %name|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% weight=97 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-number
//% line.min=1 line.max=10
//% line.min=1 line.max=12
//% deprecated=true
export function showNumber(value: number, line: number) {
showString("" + value, line);
}
/**
* Show a name, value pair on the screen on a specific line and starting at a column and the selected print style.
* @param name the value name
* @param value the numeric value
* @param line the line number to print the text at, eg: 1
* @param column the column number to print the text at (starting at 1), eg: 1
* @param printStyle print style black on white or white on black
*/
//% blockId=screenPrintValue block="show value $name|= $value|at line $line||column $column|style $printStyle"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% expandableArgumentMode="enabled"
//% help=brick/show-value
//% line.min=1 line.max=12
//% column.min=1 column.max=29
export function printValue(name: string, value: number, line: number, column: number = 1, printStyle: PrintStyle = PrintStyle.BlackOnWhite) {
value = Math.round(value * 1000) / 1000;
printString((name ? name + ": " : "") + value, line, column, printStyle);
}
/**
* Show a name, value pair on the screen
* @param value the numeric value
@ -95,7 +184,8 @@ namespace brick {
//% blockId=screenShowValue block="show value %name|= %text|at line %line"
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
//% help=brick/show-value
//% line.min=1 line.max=10
//% line.min=1 line.max=12
//% deprecated=true
export function showValue(name: string, value: number, line: number) {
value = Math.round(value * 1000) / 1000;
showString((name ? name + ": " : "") + value, line);
@ -123,11 +213,11 @@ namespace brick {
*/
//% blockId=brickShowPorts block="show ports"
//% help=brick/show-ports blockGap=8
//% weight=10 group="Screen"
//% weight=95 group="Screen"
export function showPorts() {
if (screenMode == ScreenMode.Ports) return;
screenMode = ScreenMode.Ports;
renderPorts();
control.runInParallel(function () {
while (screenMode == ScreenMode.Ports) {
@ -146,11 +236,14 @@ namespace brick {
for (let i = 0; i < 4; ++i) {
const x = i * col + 2;
screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8)
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8)
if (screenMode != ScreenMode.Ports) return;
screen.print("ABCD"[i], x, 1 * lineHeight8, 1, image.font8);
screen.print((i + 1).toString(), x, h - lineHeight8, 1, image.font8);
}
if (screenMode != ScreenMode.Ports) return;
screen.drawLine(0, 5 * lineHeight8, screen.width, 5 * lineHeight8, 1);
screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1)
screen.drawLine(0, h - 5 * lineHeight8, screen.width, h - 5 * lineHeight8, 1);
function scale(x: number) {
if (Math.abs(x) >= 5000) {
@ -167,8 +260,9 @@ namespace brick {
const data = datas[i];
const x = i * col + 2;
if (!data.actualSpeed && !data.count) continue;
screen.print(`${scale(data.actualSpeed)}%`, x, 3 * lineHeight8, 1, image.font8)
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8)
if (screenMode != ScreenMode.Ports) return;
screen.print(`${scale(data.actualSpeed)}%`, x, 3 * lineHeight8, 1, image.font8);
screen.print(`${scale(data.count)}>`, x, 4 * lineHeight8, 1, image.font8);
}
// sensors
@ -177,16 +271,16 @@ namespace brick {
const si = sis[i];
const x = (si.port() - 1) * col + 2;
const inf = si._info();
if (inf)
screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
if (screenMode != ScreenMode.Ports) return;
if (inf) screen.print(inf, x, h - 2 * lineHeight8, 1, inf.length > 4 ? image.font5 : image.font8);
}
}
export function showBoot() {
// pulse green, play startup sound, turn off light
brick.setStatusLight(StatusLight.GreenPulse);
// We pause for 100ms to give time to read sensor values, so they work in on_start block
pause(400)
// We pause to give time to read sensor values, so they work in on_start block
pause(400); // It turns out that this time is not enough for the simulator to display the LED change
// and we're ready
brick.setStatusLight(StatusLight.Off);
// always show port by default if no UI is set
@ -210,11 +304,33 @@ namespace brick {
return image;
}
/**
* Clear on the screen at a specific line.
* @param line the line number to clear at (starting at 1), eg: 1
*/
//% blockId=clearLine block="clear line $line"
//% weight=94 group="Screen" inlineInputMode="inline" blockGap=8
//% line.min=1 line.max=12
export function clearLine(line: number) {
if (screenMode != ScreenMode.ShowLines) {
screenMode = ScreenMode.ShowLines;
screen.fill(0);
}
line = (line - 1) >> 0; // line indexing starts at 1
const nlines = lineCount();
if (line < 0 || line > nlines) return; // out of screen by line
const h = lineHeight();
const y = textOffset + h * line;
screen.fillRect(0, y, screen.width, h, 0); // clear background
}
/**
* Clear the screen
*/
//% blockId=screen_clear_screen block="clear screen"
//% weight=90 group="Screen"
//% weight=93 group="Screen"
//% help=brick/clear-screen weight=1
export function clearScreen() {
screen.fill(0)

View File

@ -1,6 +1,6 @@
{
"name": "pxt-ev3",
"version": "1.4.21",
"version": "1.4.32",
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
"private": false,
"keywords": [
@ -32,21 +32,20 @@
"docs/*/*/*.md"
],
"devDependencies": {
"typescript": "2.6.1",
"react": "16.8.3",
"semantic-ui-less": "2.2.14",
"@types/bluebird": "2.0.33",
"@types/marked": "0.3.0",
"@types/node": "8.0.53",
"webfonts-generator": "^0.4.0",
"@types/jquery": "3.2.16",
"@types/react": "16.0.25",
"@types/marked": "^0.3.0",
"@types/node": "^9.3.0",
"@types/react": "16.8.25",
"@types/react-dom": "16.0.3",
"@types/web-bluetooth": "0.0.4"
"@types/web-bluetooth": "0.0.4",
"@vusion/webfonts-generator": "^0.7.1",
"react": "16.8.3",
"react-dom": "16.11.0",
"semantic-ui-less": "2.4.1",
"typescript": "^4.2.3"
},
"dependencies": {
"pxt-common-packages": "6.18.2",
"pxt-core": "5.32.3"
"pxt-common-packages": "9.2.7",
"pxt-core": "7.2.27"
},
"scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@ -77,8 +77,9 @@
"pauseUntilBlock": {
"category": "loops"
},
"bannedCategories": [
]
"breakBlock": true,
"continueBlock": true,
"bannedCategories": []
},
"compileService": {
"buildEngine": "dockermake",
@ -106,20 +107,21 @@
"driveDisplayName": "EV3",
"boardName": "LEGO® MINDSTORMS® Education EV3",
"copyrightText": "LEGO, the LEGO logo, MINDSTORMS and the MINDSTORMS EV3 logo are trademarks and/ or copyrights of the LEGO Group. ©2018 The LEGO Group. All rights reserved.",
"crowdinProject": "kindscript",
"crowdinProject": "makecode",
"selectLanguage": true,
"blocksCollapsing": true,
"highContrast": true,
"greenScreen": true,
"availableLocales": [
"en",
"de",
"ja",
"ru",
"zh-CN"
"zh-CN",
"fr"
],
"highContrast": true,
"lightToc": true,
"docMenu": [
{
"docMenu": [{
"name": "Support",
"path": "https://forum.makecode.com/"
},
@ -158,7 +160,10 @@
"extendEditor": true,
"extendFieldEditors": true,
"scriptManager": true,
"debugger": true,
"errorList": true,
"importExtensionFiles": true,
"addNewTypeScriptFile": true,
"experiments": [
"python",
"alwaysGithubItemBlocks"
@ -206,4 +211,4 @@
},
"ignoreDocsErrors": true,
"uploadDocs": true
}
}

View File

@ -1,7 +1,6 @@
CACHE MANIFEST
CACHE:
/cdn/bluebird.min.js
/cdn/pxtsim.js
/sim/common-sim.js
/sim/sim.js

View File

@ -23,7 +23,6 @@ body {
transition: none !important;
}
</style>
<script src="/cdn/bluebird.min.js"></script>
<script src="/cdn/pxtsim.js"></script>
<script src="/sim/common-sim.js"></script>
<script src="/sim/sim.js"></script>

View File

@ -21,7 +21,7 @@ namespace pxsim {
export class ColorSensorNode extends UartSensorNode {
id = NodeType.ColorSensor;
private color: number = 50;
private color: number = 0;
constructor(port: number) {
super(port);
@ -40,5 +40,13 @@ namespace pxsim {
getValue() {
return this.color;
}
setMode(mode: number) {
this.mode = mode;
if (this.mode == ColorSensorMode.RefRaw) this.color = 512;
else this.color = 50;
this.changed = true;
this.modeChanged = true;
}
}
}

View File

@ -37,7 +37,7 @@ namespace pxsim {
return Math.round(this.angle);
}
// returns the slave motor if any
// returns the secondary motor if any
getSynchedMotor() {
return this._synchedMotor;
}

View File

@ -7,6 +7,14 @@ namespace pxsim.music {
export function stopAllSounds() {
SoundMethods.stop()
}
pxsim.music.setVolume = (volume: number): void => {
pxsim.getAudioState().volume = volume;
};
export function volume() {
return pxsim.getAudioState().volume;
}
}
namespace pxsim.SoundMethods {

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"noImplicitAny": true,
"noImplicitReturns": true,
"declaration": true,
@ -8,8 +8,8 @@
"rootDir": ".",
"newLine": "LF",
"sourceMap": false,
"lib": ["dom", "dom.iterable", "scripthost", "es6"],
"types": ["bluebird"],
"lib": ["dom", "dom.iterable", "scripthost", "es2017"],
"types": [],
"typeRoots": ["../node_modules/@types"]
}
}
}

View File

@ -19,7 +19,7 @@ namespace pxsim.visuals {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
user-select: none;
}
.sim-button {
cursor: pointer;
@ -241,6 +241,8 @@ namespace pxsim.visuals {
view = new ColorGridControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.Reflected) {
view = new ColorWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.RefRaw) {
view = new ColorWheelControl(this.element, this.defs, state, port);
} else if (state.getMode() == ColorSensorMode.Ambient) {
view = new ColorWheelControl(this.element, this.defs, state, port);
}
@ -381,7 +383,7 @@ namespace pxsim.visuals {
this.screenCanvas = document.createElement("canvas");
this.screenCanvas.id = "board-screen-canvas";
this.screenCanvas.style.userSelect = "none";
this.screenCanvas.style.msUserSelect = "none";
(this.screenCanvas.style as any).msUserSelect = "none";
this.screenCanvas.style.webkitUserSelect = "none";
(this.screenCanvas.style as any).MozUserSelect = "none";
this.screenCanvas.style.position = "absolute";

View File

@ -5,8 +5,8 @@ namespace pxsim.visuals {
export class ColorGridControl extends ControlView<ColorSensorNode> {
private group: SVGGElement;
private static colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey', 'white'];
private static colorValue = [5, 4, 2, 3, 1, 7, 6];
private static colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'brown', 'white', 'none'];
private static colorValue = [5, 4, 2, 3, 1, 7, 6, 0];
private colorDivs: Element[] = [];
@ -15,7 +15,7 @@ namespace pxsim.visuals {
this.group.setAttribute("transform", `translate(2, 2.5) scale(0.6)`)
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'brown'];
let cy = -4;
for (let c = 0; c < colorIds.length; c++) {
@ -33,12 +33,19 @@ namespace pxsim.visuals {
}
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
const circle = pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-white', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
this.colorDivs.push(circle);
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` });
const noneCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'nothing-circle-wrapper' });
const whiteCircle = pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-white', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
const noneCircle = pxsim.svg.child(noneCircleWrapper, "circle", { 'class': 'sim-color-grid-circle sim-color-grid-none', 'cx': 7.5, 'cy': '16', 'r': '2', 'style': `fill: #fff; fill-opacity: 0%;` });
this.colorDivs.push(whiteCircle);
this.colorDivs.push(noneCircle);
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none; stroke: #94989b; stroke-width: 0.1px` });
pxsim.svg.child(noneCircleWrapper, "circle", { 'cx': 7.5, 'cy': '16', 'r': '2', 'style': `fill: none; stroke: #94989b; stroke-width: 0.1px` });
pointerEvents.down.forEach(evid => whiteCircleWrapper.addEventListener(evid, ev => {
this.setColor(6);
}));
pointerEvents.down.forEach(evid => noneCircleWrapper.addEventListener(evid, ev => {
this.setColor(0);
}));
return this.group;
}

View File

@ -26,8 +26,12 @@ namespace pxsim.visuals {
return 131;
}
private getMaxValue() {
return 100;
private getMaxValue(state: ColorSensorMode) {
return (state == ColorSensorMode.RefRaw ? 1023 : 100);
}
private mapValue(x: number, inMin: number, inMax: number, outMin: number, outMax: number) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
updateState() {
@ -35,10 +39,12 @@ namespace pxsim.visuals {
return;
}
const node = this.state;
const percentage = node.getValue();
const inversePercentage = this.getMaxValue() - percentage;
svg.setGradientValue(this.colorGradient, inversePercentage + "%");
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}%`;
const value = node.getValue();
let inverseValue = this.getMaxValue(node.getMode()) - value;
if (node.getMode() == ColorSensorMode.RefRaw) inverseValue = this.mapValue(inverseValue, 0, 1023, 0, 100);
svg.setGradientValue(this.colorGradient, inverseValue + "%");
this.reporter.textContent = `${parseFloat((value).toString()).toFixed(0)}`;
if (node.getMode() != ColorSensorMode.RefRaw) this.reporter.textContent += `%`;
}
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
@ -47,7 +53,7 @@ namespace pxsim.visuals {
const height = bBox.height;
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height));
const state = this.state;
state.setColor(t * this.getMaxValue());
state.setColor(t * this.getMaxValue(state.getMode()));
}
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {

View File

@ -29,6 +29,7 @@ namespace pxsim.visuals {
switch (mode) {
case ColorSensorMode.Colors: this.updateSensorLightVisual('#0062DD'); return; // blue
case ColorSensorMode.Reflected: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.RefRaw: this.updateSensorLightVisual('#F86262'); return; // red
case ColorSensorMode.Ambient: this.updateSensorLightVisual('#67C3E2'); return; // light blue
}
this.updateSensorLightVisual('#ffffff');

View File

@ -92,6 +92,11 @@
color: white;
}
/* active toggle */
.ui.item.editor-menuitem .active~.item.toggle {
background: @editorToggleColor!important;
}
.menubar .ui.item.editor-menuitem .item.toggle {
height: 45px;
}

View File

@ -17,6 +17,8 @@
specify theme name below
*/
@placeholder: 'default';
/* Global */
@site : 'pxt';
@reset : 'default';
@ -87,7 +89,7 @@
Import Theme
*******************************/
@import "theme.less";
@import (multiple) "theme.less";
@fontPath : 'fonts';