Compare commits
41 Commits
shakao/doc
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
6d222c50cb | ||
|
af263c8183 | ||
|
dd18007035 | ||
|
fba924d125 | ||
|
76257775c3 | ||
|
9be35a1034 | ||
|
2ca706df70 | ||
|
dd415019c4 | ||
|
20581513b1 | ||
|
1652fc5ffa | ||
|
8a1b6452bd | ||
|
a6712960db | ||
|
bac70eb177 | ||
|
830f5ffd77 | ||
|
aac5edd64b | ||
|
a54007d9ae | ||
|
3952cb4858 | ||
|
0226888441 | ||
|
1373e9c0bc | ||
|
cabcb048e3 | ||
|
512a441bca | ||
|
b4a18f260d | ||
|
6b3f2da72c | ||
|
b9b21328b1 | ||
|
bef4ebac43 | ||
|
617fdeb747 | ||
|
c1aead1aa9 | ||
|
bd0cf05693 | ||
|
faae7133f5 | ||
|
5289850351 | ||
|
ba6e2f7174 | ||
|
7c5dfc474f | ||
|
5ab3a6ae96 | ||
|
ed2e1f23e9 | ||
|
a157943bf7 | ||
|
40aaf0fb18 | ||
|
b26cf289c3 | ||
|
f0821f8d6c | ||
|
1db61720fc | ||
|
ec2e561427 | ||
|
36d99c8a55 |
40
.github/workflows/pxt-buildmain.yml
vendored
Normal 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
@ -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
@ -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
|
@ -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
@ -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 -->
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"appref": "v"
|
||||
"appref": "v1.4"
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ https://youtu.be/VIq8-6Egtqs
|
||||
## Supported browsers
|
||||
|
||||
* Chrome desktop, version 77 and higher, Windows 10 or Mac OS.
|
||||
* [Edge Insider desktop](https://www.microsoftedgeinsider.com), version 77 and higher, Windows 10 or Mac OS.
|
||||
* [Microsoft Edge Insider desktop](https://www.microsoftedgeinsider.com), version 77 and higher, Windows 10 or Mac OS.
|
||||
|
||||
To make sure your browser is up to date, go to the '...' menu, click "Help" then "About".
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
```
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"appref": "v1.2.27"
|
||||
"appref": "v1.2.31"
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
```
|
28
docs/static/icons/js.svg
vendored
@ -1 +1,27 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="0 0 1000 1000"><path class="st1" d="M843.77886 524.88744 880.276 501.83162 843.77886 478.86523c-17.00235-10.68208-30.88888-21.80904-41.21473-33.11451-9.88096-10.68206-18.15968-24.12333-24.65806-39.87966-6.85421-16.37895-11.75036-36.49708-14.5986-59.64157-3.0279-24.47957-4.53992-53.85527-4.53992-87.23694 0-34.8058-0.71245-60.79853-2.2264-79.49216-1.69206-21.72037-5.51915-37.92159-11.4832-49.49384-7.29949-14.06465-18.07062-23.94561-31.95715-29.46476-9.97002-3.916526-23.50072-6.854208-41.21512-8.81267-6.23121-0.89056-11.12736-3.740352-15.84501-9.524735-4.89614-5.964035-7.38854-15.311043-7.38854-27.862527 0-18.248344 3.82941-36.0518 49.84968-36.0518 28.30741 0 53.23225 5.607817 74.1515 16.735171 20.6517 10.949237 36.40803 26.171235 48.33612 46.556149 11.92847 20.384922 18.07062 44.241472 18.33779 71.035712 2.84979 158.1836 5.78593 189.8736 8.18966 199.93266 6.76518 28.04064 17.0019 49.40478 31.156 65.16073 12.72932 14.15371 28.21841 26.79424 46.02186 37.47631 12.90734 7.74439 22.25434 15.13294 27.95127 21.98715 1.603 1.87017 5.16331 8.10062 5.16331 24.65768 0 17.09139-5.34106 27.95158-17.35854 35.34012-26.97238 16.55706-46.37811 31.067-59.19637 44.33053-14.4209 14.86578-24.56869 33.47034-30.17683 55.19072-4.98481 19.40568-7.92251 46.73387-8.81267 83.40907-0.89056 34.44996-1.87018 77.53409-2.93885 129.25317-0.89056 41.92717-13.61976 74.24056-38.81139 98.89824-25.28105 24.65767-58.66273 36.67519-101.92497 36.67519-18.15968 0-31.60095-3.47319-39.79061-10.23717-6.8546-5.69688-10.05907-14.24277-10.05907-26.8833 0-8.01156 1.33584-14.95483 4.09464-21.2751 2.40451-5.43008 5.16331-9.43567 8.36779-11.92808 3.0279-2.31546 6.40931-3.6513 10.68206-4.18408 18.42647-2.49357 32.22434-5.60782 42.37208-9.70285 14.1541-5.78592 25.28106-16.82422 32.13527-31.86811 5.51915-11.92808 8.90173-27.86252 10.41529-48.42517 1.33584-17.89251 1.95924-43.08451 1.95924-76.82202 0.71244-47.26822 3.38412-84.3883 8.1006-110.38143 4.1837-23.58977 12.19526-43.88564 23.67845-60.44269 11.57224-16.82423 29.46475-32.9364 53.23226-47.89122zm-680.5 125.78114c2.49357 10.05907 5.34104 41.74907 8.18967 199.93305 0.27104 26.79424 6.49798 50.65079 18.33741 71.03571 11.83941 20.38492 27.68441 35.60691 48.33649 46.55615 20.91887 11.12697 45.84371 16.73517 74.15151 16.73517 46.02182 0 49.84968-17.80346 49.84968-36.05219 0-12.55148-2.49357-21.98716-7.38855-27.86213-4.71803-5.69727-9.61379-8.63495-15.845-9.52512-17.7144-1.95924-31.24511-4.89576-41.12606-8.81268-13.88692-5.51915-24.65767-15.40011-31.95716-29.46476-5.96443-11.57224-9.79191-27.68441-11.4832-49.49345-1.51395-18.78268-2.2264-44.7758-2.2264-79.49255 0-33.38128-1.51395-62.75698-4.53992-87.23693-2.93885-23.1445-7.83344-43.17319-14.68765-59.55253-6.49838-15.75594-14.7771-29.19758-24.65806-39.87966-10.4149-11.30508-24.21239-22.43243-41.21473-33.1145l-36.49708-22.96638 36.49708-23.05544c23.67844-14.95482 41.57095-31.06699 53.32132-47.89122 11.48318-16.55744 19.49474-36.85331 23.67843-60.44309 4.71803-25.99273 7.38856-63.20226 8.10061-110.38142 0-33.73751 0.62339-58.84007 1.95923-76.82164 1.51395-20.65209 4.89576-36.49708 10.41491-48.42556 6.85461-15.04387 17.98157-26.08218 32.04623-31.8681 10.05907-4.09464 23.9456-7.299501 42.37245-9.702847 4.27275-0.534336 7.65534-1.870176 10.68207-4.183696 3.20602-2.493568 6.05311-6.498382 8.3674-11.928477 2.84979-6.409315 4.18408-13.352592 4.18408-21.364145 0-12.640529-3.20602-21.186033-10.05907-26.883294-8.27872-6.765158-21.63132-10.236793-39.87967-10.236793-43.35168 0-76.73296 12.017139-101.92497 36.675192-25.19201 24.657677-37.92121 56.97067-38.81138 98.89785-1.06867 51.71908-2.04829 94.8036-2.93885 129.25317-0.97962 36.6752-3.82941 64.00339-8.81267 83.40908-5.60821 21.72036-15.75594 40.32494-30.17682 55.19071-12.9077 13.26392-32.31339 27.77347-59.285742 44.33092-12.017139 7.38816-17.358176 18.24835-17.358176 35.33974 0 16.64611 3.651296 22.78827 5.162925 24.65767 5.697261 6.76555 15.043878 14.15371 27.951586 21.98754 17.803457 10.68207 33.292227 23.32222 46.021807 37.47593 14.24277 15.84539 24.3909 37.12048 31.24511 65.16072z" style="stroke-width:11;stroke:#000"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 630 630">
|
||||
<!--
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011 Christopher Williams <chris@iterativedesigns.com>,
|
||||
Manuel Strehl <boldewyn@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<path d="M 0 0 L 0 630 L 630 630 L 630 0 L 0 0 z M 479.45312 285.8457 C 517.09063 285.8457 544.15617 298.95789 563.60742 333.21289 L 517.51172 362.81445 C 507.36172 344.63195 496.36813 337.44336 479.45312 337.44336 C 462.11437 337.44336 451.11914 348.4382 451.11914 362.81445 C 451.11914 380.57695 462.11508 387.76547 487.48633 398.76172 L 502.28711 405.10547 C 552.61211 426.67422 580.94531 448.66242 580.94531 498.13867 C 580.94531 551.42617 539.07969 580.60352 482.83594 580.60352 C 427.85969 580.60352 392.33625 554.38711 375 520.13086 L 423.20703 492.21875 C 435.89703 512.9425 452.38961 528.16602 481.56836 528.16602 C 506.09961 528.16602 521.74219 515.90087 521.74219 498.98438 C 521.74219 478.68563 505.67172 471.4957 478.60547 459.6582 L 463.80859 453.31055 C 421.09359 435.1293 392.75781 412.29398 392.75781 364.08398 C 392.75781 319.68023 426.58938 285.8457 479.45312 285.8457 z M 283.63867 289.23047 L 342.8418 289.23047 L 342.8418 491.36719 C 342.8418 552.68719 306.89828 580.59961 254.45703 580.59961 C 207.09789 580.59961 179.60793 556.07214 165.65234 526.47266 L 165.65039 526.47461 L 165.65039 526.46875 C 165.65101 526.47007 165.65172 526.47134 165.65234 526.47266 L 213.86328 497.29688 C 223.16453 513.78813 231.62492 527.74023 251.91992 527.74023 C 271.37367 527.74023 283.63867 520.12955 283.63867 490.5293 L 283.63867 289.23047 z "/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.6 KiB |
@ -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()
|
||||
|
@ -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(() => { });
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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_);
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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_() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": true,
|
||||
"module": "commonjs",
|
||||
|
12
libs/base/shims.d.ts
vendored
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
BIN
libs/core/jres/icons/dualMotorLarge-portAB-icon.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
libs/core/jres/icons/dualMotorLarge-portAD-icon.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
libs/core/jres/icons/dualMotorLarge-portBC-icon.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
libs/core/jres/icons/dualMotorLarge-portCD-icon.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
libs/core/jres/icons/motorLarge-portA-icon.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
libs/core/jres/icons/motorLarge-portB-icon.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
libs/core/jres/icons/motorLarge-portC-icon.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
libs/core/jres/icons/motorLarge-portD-icon.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
libs/core/jres/icons/motorMedium-portA-icon.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
libs/core/jres/icons/motorMedium-portB-icon.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
libs/core/jres/icons/motorMedium-portC-icon.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
libs/core/jres/icons/motorMedium-portD-icon.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
@ -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) {
|
||||
|
@ -28,7 +28,8 @@
|
||||
"platform.h",
|
||||
"platform.cpp",
|
||||
"dmesg.cpp",
|
||||
"integrator.ts"
|
||||
"integrator.ts",
|
||||
"cooperate.ts"
|
||||
],
|
||||
"testFiles": [
|
||||
"test.ts"
|
||||
|
@ -12,4 +12,5 @@ music.setTempo(120)
|
||||
music.noteFrequency(Note.C)
|
||||
music.beat()
|
||||
music.setVolume(50)
|
||||
```
|
||||
music.volume()
|
||||
```
|
||||
|
@ -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
@ -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
|
||||
|
@ -5,3 +5,4 @@ music.playTone(1440, 500)
|
||||
pause(500)
|
||||
music.playTone(2440, 500)
|
||||
pause(500)
|
||||
music.volume()
|
||||
|
@ -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)
|
||||
|
25
package.json
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
CACHE MANIFEST
|
||||
|
||||
CACHE:
|
||||
/cdn/bluebird.min.js
|
||||
/cdn/pxtsim.js
|
||||
/sim/common-sim.js
|
||||
/sim/sim.js
|
||||
|
@ -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>
|
||||
|
5
sim/public/workerConfig.js
Normal file
@ -0,0 +1,5 @@
|
||||
self.setSimulatorWorkerOptions({
|
||||
urls: [
|
||||
"/sim/common-sim.js"
|
||||
]
|
||||
})
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
@ -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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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';
|
||||
|
||||
|