pxt-core 8.4.2 → 8.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/built/backendutils.js +1 -0
- package/built/cli.js +83 -75
- package/built/pxt.js +1264 -176
- package/built/pxtblockly.js +323 -40
- package/built/pxtblocks.d.ts +30 -7
- package/built/pxtblocks.js +324 -41
- package/built/pxtlib.d.ts +91 -5
- package/built/pxtlib.js +1173 -98
- package/built/pxtsim.js +8 -3
- package/built/server.js +4 -0
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/multiplayer/css/main.2dd69ed8.css +4 -0
- package/built/web/multiplayer/js/main.f3b8f930.js +2 -0
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtblockly.js +1 -1
- package/built/web/pxtblocks.js +1 -1
- package/built/web/pxtembed.js +2 -2
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtsim.js +1 -1
- package/built/web/pxtworker.js +2 -2
- package/built/web/react-common-authcode.css +4 -6993
- package/built/web/react-common-multiplayer.css +13 -0
- package/built/web/react-common-skillmap.css +1 -1
- package/built/web/rtlreact-common-authcode.css +13 -0
- package/built/web/rtlreact-common-multiplayer.css +13 -0
- package/built/web/rtlreact-common-skillmap.css +1 -1
- package/built/web/rtlsemantic.css +1 -1
- package/built/web/semantic.css +1 -1
- package/built/web/skillmap/js/main.a6cf40e1.chunk.js +1 -0
- package/common-docs/identity/sign-in.md +17 -3
- package/common-docs/static/music-editor/apple.png +0 -0
- package/common-docs/static/music-editor/burger.png +0 -0
- package/common-docs/static/music-editor/cake.png +0 -0
- package/common-docs/static/music-editor/car.png +0 -0
- package/common-docs/static/music-editor/cat.png +0 -0
- package/common-docs/static/music-editor/cherry.png +0 -0
- package/common-docs/static/music-editor/clam.png +0 -0
- package/common-docs/static/music-editor/computer.png +0 -0
- package/common-docs/static/music-editor/crab.png +0 -0
- package/common-docs/static/music-editor/dog.png +0 -0
- package/common-docs/static/music-editor/duck.png +0 -0
- package/common-docs/static/music-editor/egg.png +0 -0
- package/common-docs/static/music-editor/explosion.png +0 -0
- package/common-docs/static/music-editor/fish.png +0 -0
- package/common-docs/static/music-editor/ice-cream.png +0 -0
- package/common-docs/static/music-editor/lemon.png +0 -0
- package/common-docs/static/music-editor/metronomeWorker.js +35 -0
- package/common-docs/static/music-editor/snake.png +0 -0
- package/common-docs/static/music-editor/star.png +0 -0
- package/common-docs/static/music-editor/strawberry.png +0 -0
- package/common-docs/static/music-editor/taco.png +0 -0
- package/common-docs/static/music-editor/treble-clef.svg +1 -0
- package/package.json +4 -2
- package/react-common/components/controls/Input.tsx +7 -3
- package/react-common/styles/controls/Button.less +9 -0
- package/react-common/styles/react-common-authcode-core.less +1 -1
- package/react-common/styles/react-common-authcode.less +1 -1
- package/react-common/styles/react-common-multiplayer-core.less +10 -0
- package/react-common/styles/react-common-multiplayer.less +12 -0
- package/theme/highcontrast.less +6 -0
- package/theme/music-editor/EditControls.less +22 -0
- package/theme/music-editor/MusicEditor.less +25 -0
- package/theme/music-editor/Note.less +16 -0
- package/theme/music-editor/NoteGroup.less +7 -0
- package/theme/music-editor/PlaybackControls.less +55 -0
- package/theme/music-editor/ScrollableWorkspace.less +3 -0
- package/theme/music-editor/Staff.less +31 -0
- package/theme/music-editor/Track.less +0 -0
- package/theme/music-editor/TrackSelector.less +48 -0
- package/theme/music-editor/Workspace.less +3 -0
- package/theme/pxt.less +1 -0
- package/theme/tutorial-sidebar.less +3 -0
- package/webapp/public/multiplayer.html +1 -0
- package/webapp/public/skillmap.html +1 -1
- package/built/web/skillmap/js/main.6eec9e0f.chunk.js +0 -1
package/built/pxtblockly.js
CHANGED
|
@@ -5963,6 +5963,7 @@ var pxt;
|
|
|
5963
5963
|
registerFieldEditor('melody', pxtblockly.FieldCustomMelody);
|
|
5964
5964
|
registerFieldEditor('soundeffect', pxtblockly.FieldSoundEffect);
|
|
5965
5965
|
registerFieldEditor('autocomplete', pxtblockly.FieldAutoComplete);
|
|
5966
|
+
registerFieldEditor('musiceditor', pxtblockly.FieldMusicEditor);
|
|
5966
5967
|
}
|
|
5967
5968
|
blocks.initFieldEditors = initFieldEditors;
|
|
5968
5969
|
function registerFieldEditor(selector, field, validator) {
|
|
@@ -11584,50 +11585,159 @@ var pxtblockly;
|
|
|
11584
11585
|
const project = pxt.react.getTilemapProject();
|
|
11585
11586
|
pxt.sprite.addMissingTilemapTilesAndReferences(project, this.asset);
|
|
11586
11587
|
break;
|
|
11588
|
+
case "song" /* pxt.AssetType.Song */:
|
|
11589
|
+
editorKind = "music-editor";
|
|
11590
|
+
params.temporaryAssets = pxtblockly.getTemporaryAssets(this.sourceBlock_.workspace, "song" /* pxt.AssetType.Song */);
|
|
11591
|
+
pxtblockly.setMelodyEditorOpen(this.sourceBlock_, true);
|
|
11592
|
+
break;
|
|
11593
|
+
}
|
|
11594
|
+
if (this.isFullscreen()) {
|
|
11595
|
+
this.showEditorFullscreen(editorKind, params);
|
|
11596
|
+
}
|
|
11597
|
+
else {
|
|
11598
|
+
this.showEditorInWidgetDiv(editorKind, params);
|
|
11587
11599
|
}
|
|
11600
|
+
}
|
|
11601
|
+
showEditorFullscreen(editorKind, params) {
|
|
11588
11602
|
const fv = pxt.react.getFieldEditorView(editorKind, this.asset, params);
|
|
11589
11603
|
if (this.undoRedoState) {
|
|
11590
11604
|
fv.restorePersistentData(this.undoRedoState);
|
|
11591
11605
|
}
|
|
11592
11606
|
pxt.react.getTilemapProject().pushUndo();
|
|
11593
11607
|
fv.onHide(() => {
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
+
this.onFieldEditorHide(fv);
|
|
11609
|
+
});
|
|
11610
|
+
fv.show();
|
|
11611
|
+
}
|
|
11612
|
+
showEditorInWidgetDiv(editorKind, params) {
|
|
11613
|
+
let bbox;
|
|
11614
|
+
// This is due to the changes in https://github.com/microsoft/pxt-blockly/pull/289
|
|
11615
|
+
// which caused the widgetdiv to jump around if any fields underneath changed size
|
|
11616
|
+
let widgetOwner = {
|
|
11617
|
+
getScaledBBox: () => bbox
|
|
11618
|
+
};
|
|
11619
|
+
Blockly.WidgetDiv.show(widgetOwner, this.sourceBlock_.RTL, () => {
|
|
11620
|
+
if (document.activeElement && document.activeElement.tagName === "INPUT")
|
|
11621
|
+
document.activeElement.blur();
|
|
11622
|
+
fv.hide();
|
|
11623
|
+
widgetDiv.classList.remove("sound-effect-editor-widget");
|
|
11624
|
+
widgetDiv.style.transform = "";
|
|
11625
|
+
widgetDiv.style.position = "";
|
|
11626
|
+
widgetDiv.style.left = "";
|
|
11627
|
+
widgetDiv.style.top = "";
|
|
11628
|
+
widgetDiv.style.width = "";
|
|
11629
|
+
widgetDiv.style.height = "";
|
|
11630
|
+
widgetDiv.style.opacity = "";
|
|
11631
|
+
widgetDiv.style.transition = "";
|
|
11632
|
+
widgetDiv.style.alignItems = "";
|
|
11633
|
+
this.onFieldEditorHide(fv);
|
|
11634
|
+
});
|
|
11635
|
+
const widgetDiv = Blockly.WidgetDiv.DIV;
|
|
11636
|
+
const fv = pxt.react.getFieldEditorView(editorKind, this.asset, params, widgetDiv);
|
|
11637
|
+
const block = this.sourceBlock_;
|
|
11638
|
+
const bounds = block.getBoundingRectangle();
|
|
11639
|
+
const coord = pxtblockly.workspaceToScreenCoordinates(block.workspace, new Blockly.utils.Coordinate(bounds.right, bounds.top));
|
|
11640
|
+
const animationDistance = 20;
|
|
11641
|
+
const left = coord.x - 400;
|
|
11642
|
+
const top = coord.y + 60 - animationDistance;
|
|
11643
|
+
widgetDiv.style.opacity = "0";
|
|
11644
|
+
widgetDiv.classList.add("sound-effect-editor-widget");
|
|
11645
|
+
widgetDiv.style.position = "absolute";
|
|
11646
|
+
widgetDiv.style.left = left + "px";
|
|
11647
|
+
widgetDiv.style.top = top + "px";
|
|
11648
|
+
widgetDiv.style.width = "50rem";
|
|
11649
|
+
widgetDiv.style.height = "34.25rem";
|
|
11650
|
+
widgetDiv.style.display = "flex";
|
|
11651
|
+
widgetDiv.style.alignItems = "center";
|
|
11652
|
+
widgetDiv.style.transition = "transform 0.25s ease 0s, opacity 0.25s ease 0s";
|
|
11653
|
+
widgetDiv.style.borderRadius = "";
|
|
11654
|
+
fv.onHide(() => {
|
|
11655
|
+
Blockly.WidgetDiv.hideIfOwner(widgetOwner);
|
|
11656
|
+
});
|
|
11657
|
+
fv.show();
|
|
11658
|
+
const divBounds = widgetDiv.getBoundingClientRect();
|
|
11659
|
+
const injectDivBounds = block.workspace.getInjectionDiv().getBoundingClientRect();
|
|
11660
|
+
if (divBounds.height > injectDivBounds.height) {
|
|
11661
|
+
widgetDiv.style.height = "";
|
|
11662
|
+
widgetDiv.style.top = `calc(1rem - ${animationDistance}px)`;
|
|
11663
|
+
widgetDiv.style.bottom = `calc(1rem + ${animationDistance}px)`;
|
|
11664
|
+
}
|
|
11665
|
+
else {
|
|
11666
|
+
if (divBounds.bottom > injectDivBounds.bottom || divBounds.top < injectDivBounds.top) {
|
|
11667
|
+
// This editor is pretty tall, so just center vertically on the inject div
|
|
11668
|
+
widgetDiv.style.top = (injectDivBounds.top + (injectDivBounds.height / 2) - (divBounds.height / 2)) - animationDistance + "px";
|
|
11669
|
+
}
|
|
11670
|
+
}
|
|
11671
|
+
const toolboxWidth = block.workspace.getToolbox().getWidth();
|
|
11672
|
+
const workspaceLeft = injectDivBounds.left + toolboxWidth;
|
|
11673
|
+
if (divBounds.width > injectDivBounds.width - toolboxWidth) {
|
|
11674
|
+
widgetDiv.style.width = "";
|
|
11675
|
+
widgetDiv.style.left = "1rem";
|
|
11676
|
+
widgetDiv.style.right = "1rem";
|
|
11677
|
+
}
|
|
11678
|
+
else {
|
|
11679
|
+
// Check to see if we are bleeding off the right side of the canvas
|
|
11680
|
+
if (divBounds.left + divBounds.width >= injectDivBounds.right) {
|
|
11681
|
+
// If so, try and place to the left of the block instead of the right
|
|
11682
|
+
const blockLeft = pxtblockly.workspaceToScreenCoordinates(block.workspace, new Blockly.utils.Coordinate(bounds.left, bounds.top));
|
|
11683
|
+
if (blockLeft.x - divBounds.width - 20 > workspaceLeft) {
|
|
11684
|
+
widgetDiv.style.left = (blockLeft.x - divBounds.width - 20) + "px";
|
|
11608
11685
|
}
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
this.asset = result;
|
|
11613
|
-
const lastRevision = project.revision();
|
|
11614
|
-
this.onEditorClose(this.asset);
|
|
11615
|
-
this.updateAssetListener();
|
|
11616
|
-
this.updateAssetMeta();
|
|
11617
|
-
this.redrawPreview();
|
|
11618
|
-
this.undoRedoState = fv.getPersistentData();
|
|
11619
|
-
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
|
11620
|
-
const event = new BlocklyTilemapChange(this.sourceBlock_, 'field', this.name, old, this.getValue(), lastRevision, project.revision());
|
|
11621
|
-
if (oldId !== newId) {
|
|
11622
|
-
event.oldAssetId = oldId;
|
|
11623
|
-
event.newAssetId = newId;
|
|
11624
|
-
}
|
|
11625
|
-
Blockly.Events.fire(event);
|
|
11686
|
+
else {
|
|
11687
|
+
// As a last resort, just center on the inject div
|
|
11688
|
+
widgetDiv.style.left = (workspaceLeft + ((injectDivBounds.width - toolboxWidth) / 2) - divBounds.width / 2) + "px";
|
|
11626
11689
|
}
|
|
11627
|
-
this.pendingEdit = false;
|
|
11628
11690
|
}
|
|
11691
|
+
else if (divBounds.left < injectDivBounds.left) {
|
|
11692
|
+
widgetDiv.style.left = workspaceLeft + "px";
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11695
|
+
const finalDimensions = widgetDiv.getBoundingClientRect();
|
|
11696
|
+
bbox = new Blockly.utils.Rect(finalDimensions.top, finalDimensions.bottom, finalDimensions.left, finalDimensions.right);
|
|
11697
|
+
requestAnimationFrame(() => {
|
|
11698
|
+
widgetDiv.style.opacity = "1";
|
|
11699
|
+
widgetDiv.style.transform = `translateY(${animationDistance}px)`;
|
|
11629
11700
|
});
|
|
11630
|
-
|
|
11701
|
+
}
|
|
11702
|
+
onFieldEditorHide(fv) {
|
|
11703
|
+
var _a;
|
|
11704
|
+
const result = fv.getResult();
|
|
11705
|
+
const project = pxt.react.getTilemapProject();
|
|
11706
|
+
if (this.asset.type === "song" /* pxt.AssetType.Song */) {
|
|
11707
|
+
pxtblockly.setMelodyEditorOpen(this.sourceBlock_, false);
|
|
11708
|
+
}
|
|
11709
|
+
if (result) {
|
|
11710
|
+
const old = this.getValue();
|
|
11711
|
+
if (pxt.assetEquals(this.asset, result))
|
|
11712
|
+
return;
|
|
11713
|
+
const oldId = isTemporaryAsset(this.asset) ? null : this.asset.id;
|
|
11714
|
+
let newId = isTemporaryAsset(result) ? null : result.id;
|
|
11715
|
+
if (!oldId && newId === this.sourceBlock_.id) {
|
|
11716
|
+
// The temporary assets we create just use the block id as the id; give it something
|
|
11717
|
+
// a little nicer
|
|
11718
|
+
result.id = project.generateNewID(result.type);
|
|
11719
|
+
newId = result.id;
|
|
11720
|
+
}
|
|
11721
|
+
this.pendingEdit = true;
|
|
11722
|
+
if ((_a = result.meta) === null || _a === void 0 ? void 0 : _a.displayName)
|
|
11723
|
+
this.disposeOfTemporaryAsset();
|
|
11724
|
+
this.asset = result;
|
|
11725
|
+
const lastRevision = project.revision();
|
|
11726
|
+
this.onEditorClose(this.asset);
|
|
11727
|
+
this.updateAssetListener();
|
|
11728
|
+
this.updateAssetMeta();
|
|
11729
|
+
this.redrawPreview();
|
|
11730
|
+
this.undoRedoState = fv.getPersistentData();
|
|
11731
|
+
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
|
11732
|
+
const event = new BlocklyTilemapChange(this.sourceBlock_, 'field', this.name, old, this.getValue(), lastRevision, project.revision());
|
|
11733
|
+
if (oldId !== newId) {
|
|
11734
|
+
event.oldAssetId = oldId;
|
|
11735
|
+
event.newAssetId = newId;
|
|
11736
|
+
}
|
|
11737
|
+
Blockly.Events.fire(event);
|
|
11738
|
+
}
|
|
11739
|
+
this.pendingEdit = false;
|
|
11740
|
+
}
|
|
11631
11741
|
}
|
|
11632
11742
|
render_() {
|
|
11633
11743
|
if (this.isGreyBlock && !this.textElement_) {
|
|
@@ -11725,12 +11835,17 @@ var pxtblockly;
|
|
|
11725
11835
|
case "tilemap" /* pxt.AssetType.Tilemap */:
|
|
11726
11836
|
dataURI = pxtblockly.tilemapToImageURI(this.asset.data, PREVIEW_WIDTH, this.lightMode);
|
|
11727
11837
|
break;
|
|
11838
|
+
case "song" /* pxt.AssetType.Song */:
|
|
11839
|
+
dataURI = pxtblockly.songToDataURI(this.asset.song, 60, 20, this.lightMode);
|
|
11840
|
+
break;
|
|
11841
|
+
}
|
|
11842
|
+
if (dataURI) {
|
|
11843
|
+
const img = new svg.Image()
|
|
11844
|
+
.src(dataURI)
|
|
11845
|
+
.at(X_PADDING + BG_PADDING, Y_PADDING + BG_PADDING)
|
|
11846
|
+
.size(PREVIEW_WIDTH, PREVIEW_WIDTH);
|
|
11847
|
+
this.fieldGroup_.appendChild(img.el);
|
|
11728
11848
|
}
|
|
11729
|
-
const img = new svg.Image()
|
|
11730
|
-
.src(dataURI)
|
|
11731
|
-
.at(X_PADDING + BG_PADDING, Y_PADDING + BG_PADDING)
|
|
11732
|
-
.size(PREVIEW_WIDTH, PREVIEW_WIDTH);
|
|
11733
|
-
this.fieldGroup_.appendChild(img.el);
|
|
11734
11849
|
}
|
|
11735
11850
|
}
|
|
11736
11851
|
parseValueText(newText) {
|
|
@@ -11821,6 +11936,9 @@ var pxtblockly;
|
|
|
11821
11936
|
pxt.react.getTilemapProject().addChangeListener(this.asset, this.assetChangeListener);
|
|
11822
11937
|
}
|
|
11823
11938
|
}
|
|
11939
|
+
isFullscreen() {
|
|
11940
|
+
return true;
|
|
11941
|
+
}
|
|
11824
11942
|
}
|
|
11825
11943
|
pxtblockly.FieldAssetEditor = FieldAssetEditor;
|
|
11826
11944
|
function isTemporaryAsset(asset) {
|
|
@@ -13887,13 +14005,13 @@ var pxtblockly;
|
|
|
13887
14005
|
this.prevString = this.getValue();
|
|
13888
14006
|
// The webapp listens to this event and stops the simulator so that you don't get the melody
|
|
13889
14007
|
// playing twice (once in the editor and once when the code runs in the sim)
|
|
13890
|
-
|
|
14008
|
+
pxtblockly.setMelodyEditorOpen(this.sourceBlock_, true);
|
|
13891
14009
|
Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_, () => {
|
|
13892
14010
|
this.onEditorClose();
|
|
13893
14011
|
// revert all style attributes for dropdown div
|
|
13894
14012
|
pxt.BrowserUtils.removeClass(contentDiv, "melody-content-div");
|
|
13895
14013
|
pxt.BrowserUtils.removeClass(contentDiv.parentElement, "melody-editor-dropdown");
|
|
13896
|
-
|
|
14014
|
+
pxtblockly.setMelodyEditorOpen(this.sourceBlock_, false);
|
|
13897
14015
|
});
|
|
13898
14016
|
}
|
|
13899
14017
|
getValue() {
|
|
@@ -14561,6 +14679,116 @@ var pxtblockly;
|
|
|
14561
14679
|
return "#DCDCDC";
|
|
14562
14680
|
}
|
|
14563
14681
|
})(pxtblockly || (pxtblockly = {}));
|
|
14682
|
+
/// <reference path="../../built/pxtlib.d.ts" />
|
|
14683
|
+
/// <reference path="./field_asset.ts" />
|
|
14684
|
+
var pxtblockly;
|
|
14685
|
+
(function (pxtblockly) {
|
|
14686
|
+
var svg = pxt.svgUtil;
|
|
14687
|
+
const PREVIEW_HEIGHT = 32;
|
|
14688
|
+
const X_PADDING = 5;
|
|
14689
|
+
const Y_PADDING = 1;
|
|
14690
|
+
const BG_PADDING = 4;
|
|
14691
|
+
const BG_HEIGHT = BG_PADDING * 2 + PREVIEW_HEIGHT;
|
|
14692
|
+
const TOTAL_HEIGHT = Y_PADDING * 2 + BG_PADDING * 2 + PREVIEW_HEIGHT;
|
|
14693
|
+
class FieldMusicEditor extends pxtblockly.FieldAssetEditor {
|
|
14694
|
+
getAssetType() {
|
|
14695
|
+
return "song" /* pxt.AssetType.Song */;
|
|
14696
|
+
}
|
|
14697
|
+
createNewAsset(text) {
|
|
14698
|
+
const project = pxt.react.getTilemapProject();
|
|
14699
|
+
if (text) {
|
|
14700
|
+
const asset = pxt.lookupProjectAssetByTSReference(text, project);
|
|
14701
|
+
if (asset)
|
|
14702
|
+
return asset;
|
|
14703
|
+
}
|
|
14704
|
+
if (this.getBlockData()) {
|
|
14705
|
+
return project.lookupAsset("song" /* pxt.AssetType.Song */, this.getBlockData());
|
|
14706
|
+
}
|
|
14707
|
+
let song;
|
|
14708
|
+
if (text) {
|
|
14709
|
+
const match = /^\s*hex\s*`([a-fA-F0-9]+)`\s*(?:;?)\s*$/.exec(text);
|
|
14710
|
+
if (match) {
|
|
14711
|
+
song = pxt.assets.music.decodeSongFromHex(match[1]);
|
|
14712
|
+
}
|
|
14713
|
+
}
|
|
14714
|
+
else {
|
|
14715
|
+
song = pxt.assets.music.getEmptySong(2);
|
|
14716
|
+
}
|
|
14717
|
+
if (!song) {
|
|
14718
|
+
this.isGreyBlock = true;
|
|
14719
|
+
this.valueText = text;
|
|
14720
|
+
return undefined;
|
|
14721
|
+
}
|
|
14722
|
+
else {
|
|
14723
|
+
// Restore all of the unused tracks
|
|
14724
|
+
pxt.assets.music.inflateSong(song);
|
|
14725
|
+
}
|
|
14726
|
+
const newAsset = {
|
|
14727
|
+
internalID: -1,
|
|
14728
|
+
id: this.sourceBlock_.id,
|
|
14729
|
+
type: "song" /* pxt.AssetType.Song */,
|
|
14730
|
+
meta: {},
|
|
14731
|
+
song
|
|
14732
|
+
};
|
|
14733
|
+
return newAsset;
|
|
14734
|
+
}
|
|
14735
|
+
render_() {
|
|
14736
|
+
super.render_();
|
|
14737
|
+
if (!this.isGreyBlock) {
|
|
14738
|
+
this.size_.height = TOTAL_HEIGHT;
|
|
14739
|
+
this.size_.width = X_PADDING * 2 + BG_PADDING * 2 + this.previewWidth();
|
|
14740
|
+
}
|
|
14741
|
+
}
|
|
14742
|
+
getValueText() {
|
|
14743
|
+
if (this.asset && !this.isTemporaryAsset()) {
|
|
14744
|
+
return pxt.getTSReferenceForAsset(this.asset);
|
|
14745
|
+
}
|
|
14746
|
+
return this.asset ? `hex\`${pxt.assets.music.encodeSongToHex(this.asset.song)}\`` : "";
|
|
14747
|
+
}
|
|
14748
|
+
parseFieldOptions(opts) {
|
|
14749
|
+
return {};
|
|
14750
|
+
}
|
|
14751
|
+
isFullscreen() {
|
|
14752
|
+
return false;
|
|
14753
|
+
}
|
|
14754
|
+
redrawPreview() {
|
|
14755
|
+
var _a;
|
|
14756
|
+
if (!this.fieldGroup_)
|
|
14757
|
+
return;
|
|
14758
|
+
pxsim.U.clear(this.fieldGroup_);
|
|
14759
|
+
if (this.isGreyBlock) {
|
|
14760
|
+
super.redrawPreview();
|
|
14761
|
+
return;
|
|
14762
|
+
}
|
|
14763
|
+
const totalWidth = X_PADDING * 2 + BG_PADDING * 2 + this.previewWidth();
|
|
14764
|
+
const bg = new svg.Rect()
|
|
14765
|
+
.at(X_PADDING, Y_PADDING)
|
|
14766
|
+
.size(BG_PADDING * 2 + this.previewWidth(), BG_HEIGHT)
|
|
14767
|
+
.setClass("blocklySpriteField")
|
|
14768
|
+
.stroke("#898989", 1)
|
|
14769
|
+
.corner(4);
|
|
14770
|
+
this.fieldGroup_.appendChild(bg.el);
|
|
14771
|
+
if (this.asset) {
|
|
14772
|
+
const dataURI = pxtblockly.songToDataURI(this.asset.song, this.previewWidth(), PREVIEW_HEIGHT, this.lightMode);
|
|
14773
|
+
if (dataURI) {
|
|
14774
|
+
const img = new svg.Image()
|
|
14775
|
+
.src(dataURI)
|
|
14776
|
+
.at(X_PADDING + BG_PADDING, Y_PADDING + BG_PADDING)
|
|
14777
|
+
.size(this.previewWidth(), PREVIEW_HEIGHT);
|
|
14778
|
+
this.fieldGroup_.appendChild(img.el);
|
|
14779
|
+
}
|
|
14780
|
+
}
|
|
14781
|
+
if (((_a = this.size_) === null || _a === void 0 ? void 0 : _a.width) != totalWidth) {
|
|
14782
|
+
this.forceRerender();
|
|
14783
|
+
}
|
|
14784
|
+
}
|
|
14785
|
+
previewWidth() {
|
|
14786
|
+
const measures = this.asset ? this.asset.song.measures : 2;
|
|
14787
|
+
return measures * PREVIEW_HEIGHT;
|
|
14788
|
+
}
|
|
14789
|
+
}
|
|
14790
|
+
pxtblockly.FieldMusicEditor = FieldMusicEditor;
|
|
14791
|
+
})(pxtblockly || (pxtblockly = {}));
|
|
14564
14792
|
/// <reference path="../../localtypings/pxtblockly.d.ts" />
|
|
14565
14793
|
var pxtblockly;
|
|
14566
14794
|
(function (pxtblockly) {
|
|
@@ -17096,6 +17324,54 @@ var pxtblockly;
|
|
|
17096
17324
|
return canvas.toDataURL();
|
|
17097
17325
|
}
|
|
17098
17326
|
pxtblockly.tilemapToImageURI = tilemapToImageURI;
|
|
17327
|
+
function songToDataURI(song, width, height, lightMode, maxMeasures) {
|
|
17328
|
+
const colors = pxt.appTarget.runtime.palette.slice();
|
|
17329
|
+
const canvas = document.createElement("canvas");
|
|
17330
|
+
canvas.width = width;
|
|
17331
|
+
canvas.height = height;
|
|
17332
|
+
let context;
|
|
17333
|
+
if (lightMode) {
|
|
17334
|
+
context = canvas.getContext("2d", { alpha: false });
|
|
17335
|
+
context.fillStyle = "#dedede";
|
|
17336
|
+
context.fillRect(0, 0, width, height);
|
|
17337
|
+
}
|
|
17338
|
+
else {
|
|
17339
|
+
context = canvas.getContext("2d");
|
|
17340
|
+
}
|
|
17341
|
+
const trackColors = [
|
|
17342
|
+
5,
|
|
17343
|
+
11,
|
|
17344
|
+
5,
|
|
17345
|
+
4,
|
|
17346
|
+
2,
|
|
17347
|
+
6,
|
|
17348
|
+
14,
|
|
17349
|
+
2,
|
|
17350
|
+
5,
|
|
17351
|
+
1, // explosion
|
|
17352
|
+
];
|
|
17353
|
+
maxMeasures = maxMeasures || song.measures;
|
|
17354
|
+
const cellWidth = Math.max(Math.floor(width / (song.beatsPerMeasure * maxMeasures * 2)), 1);
|
|
17355
|
+
const cellsShown = Math.floor(width / cellWidth);
|
|
17356
|
+
const cellHeight = Math.max(Math.floor(height / 12), 1);
|
|
17357
|
+
const notesShown = Math.floor(height / cellHeight);
|
|
17358
|
+
for (const track of song.tracks) {
|
|
17359
|
+
for (const noteEvent of track.notes) {
|
|
17360
|
+
const col = Math.floor(noteEvent.startTick / (song.ticksPerBeat / 2));
|
|
17361
|
+
if (col > cellsShown)
|
|
17362
|
+
break;
|
|
17363
|
+
for (const note of noteEvent.notes) {
|
|
17364
|
+
const row = 12 - (note % 12);
|
|
17365
|
+
if (row > notesShown)
|
|
17366
|
+
continue;
|
|
17367
|
+
context.fillStyle = colors[trackColors[track.id || song.tracks.indexOf(track)]];
|
|
17368
|
+
context.fillRect(col * cellWidth, row * cellHeight, cellWidth, cellHeight);
|
|
17369
|
+
}
|
|
17370
|
+
}
|
|
17371
|
+
}
|
|
17372
|
+
return canvas.toDataURL();
|
|
17373
|
+
}
|
|
17374
|
+
pxtblockly.songToDataURI = songToDataURI;
|
|
17099
17375
|
function deleteTilesetTileIfExists(ws, tile) {
|
|
17100
17376
|
const existing = ws.getVariablesOfType(pxt.sprite.BLOCKLY_TILESET_TYPE);
|
|
17101
17377
|
for (const model of existing) {
|
|
@@ -17231,10 +17507,17 @@ var pxtblockly;
|
|
|
17231
17507
|
case "animation" /* pxt.AssetType.Animation */:
|
|
17232
17508
|
return getAllFields(workspace, field => field instanceof pxtblockly.FieldAnimationEditor && field.isTemporaryAsset())
|
|
17233
17509
|
.map(f => f.ref.getAsset());
|
|
17510
|
+
case "song" /* pxt.AssetType.Song */:
|
|
17511
|
+
return getAllFields(workspace, field => field instanceof pxtblockly.FieldMusicEditor && field.isTemporaryAsset())
|
|
17512
|
+
.map(f => f.ref.getAsset());
|
|
17234
17513
|
default: return [];
|
|
17235
17514
|
}
|
|
17236
17515
|
}
|
|
17237
17516
|
pxtblockly.getTemporaryAssets = getTemporaryAssets;
|
|
17517
|
+
function setMelodyEditorOpen(block, isOpen) {
|
|
17518
|
+
Blockly.Events.fire(new Blockly.Events.Ui(block, "melody-editor", !isOpen, isOpen));
|
|
17519
|
+
}
|
|
17520
|
+
pxtblockly.setMelodyEditorOpen = setMelodyEditorOpen;
|
|
17238
17521
|
function workspaceToScreenCoordinates(ws, wsCoordinates) {
|
|
17239
17522
|
// The position in pixels relative to the origin of the
|
|
17240
17523
|
// main workspace.
|
package/built/pxtblocks.d.ts
CHANGED
|
@@ -411,15 +411,15 @@ declare namespace pxtblockly {
|
|
|
411
411
|
}
|
|
412
412
|
declare namespace pxtblockly {
|
|
413
413
|
export interface FieldAssetEditorOptions {
|
|
414
|
-
initWidth
|
|
415
|
-
initHeight
|
|
416
|
-
disableResize
|
|
414
|
+
initWidth?: string;
|
|
415
|
+
initHeight?: string;
|
|
416
|
+
disableResize?: string;
|
|
417
417
|
}
|
|
418
418
|
interface ParsedFieldAssetEditorOptions {
|
|
419
|
-
initWidth
|
|
420
|
-
initHeight
|
|
421
|
-
disableResize
|
|
422
|
-
lightMode
|
|
419
|
+
initWidth?: number;
|
|
420
|
+
initHeight?: number;
|
|
421
|
+
disableResize?: boolean;
|
|
422
|
+
lightMode?: boolean;
|
|
423
423
|
}
|
|
424
424
|
export abstract class FieldAssetEditor<U extends FieldAssetEditorOptions, V extends ParsedFieldAssetEditorOptions> extends FieldBase<U> {
|
|
425
425
|
protected asset: pxt.Asset;
|
|
@@ -437,6 +437,9 @@ declare namespace pxtblockly {
|
|
|
437
437
|
onInit(): void;
|
|
438
438
|
onValueChanged(newValue: string): string;
|
|
439
439
|
showEditor_(): void;
|
|
440
|
+
protected showEditorFullscreen(editorKind: string, params: any): void;
|
|
441
|
+
protected showEditorInWidgetDiv(editorKind: string, params: any): void;
|
|
442
|
+
protected onFieldEditorHide(fv: pxt.react.FieldEditorView<pxt.Asset>): void;
|
|
440
443
|
render_(): void;
|
|
441
444
|
getDisplayText_(): string;
|
|
442
445
|
updateEditable(): void;
|
|
@@ -454,6 +457,7 @@ declare namespace pxtblockly {
|
|
|
454
457
|
protected updateAssetMeta(): void;
|
|
455
458
|
protected updateAssetListener(): void;
|
|
456
459
|
protected assetChangeListener: () => void;
|
|
460
|
+
protected isFullscreen(): boolean;
|
|
457
461
|
}
|
|
458
462
|
export class BlocklyTilemapChange extends Blockly.Events.BlockChange {
|
|
459
463
|
protected oldRevision: number;
|
|
@@ -981,6 +985,23 @@ declare namespace pxtblockly {
|
|
|
981
985
|
cy: number;
|
|
982
986
|
}
|
|
983
987
|
}
|
|
988
|
+
declare namespace pxtblockly {
|
|
989
|
+
export interface FieldMusicEditorOptions {
|
|
990
|
+
}
|
|
991
|
+
interface ParsedFieldMusicEditorOptions {
|
|
992
|
+
}
|
|
993
|
+
export class FieldMusicEditor extends FieldAssetEditor<FieldMusicEditorOptions, ParsedFieldMusicEditorOptions> {
|
|
994
|
+
protected getAssetType(): pxt.AssetType;
|
|
995
|
+
protected createNewAsset(text?: string): pxt.Asset;
|
|
996
|
+
render_(): void;
|
|
997
|
+
protected getValueText(): string;
|
|
998
|
+
protected parseFieldOptions(opts: FieldMusicEditorOptions): ParsedFieldMusicEditorOptions;
|
|
999
|
+
protected isFullscreen(): boolean;
|
|
1000
|
+
protected redrawPreview(): void;
|
|
1001
|
+
protected previewWidth(): number;
|
|
1002
|
+
}
|
|
1003
|
+
export {};
|
|
1004
|
+
}
|
|
984
1005
|
declare namespace pxtblockly {
|
|
985
1006
|
interface FieldNoteOptions extends Blockly.FieldCustomOptions {
|
|
986
1007
|
editorColour?: string;
|
|
@@ -1498,6 +1519,7 @@ declare namespace pxtblockly {
|
|
|
1498
1519
|
*/
|
|
1499
1520
|
function bitmapToImageURI(frame: pxt.sprite.Bitmap, sideLength: number, lightMode: boolean): string;
|
|
1500
1521
|
function tilemapToImageURI(data: pxt.sprite.TilemapData, sideLength: number, lightMode: boolean): string;
|
|
1522
|
+
function songToDataURI(song: pxt.assets.music.Song, width: number, height: number, lightMode: boolean, maxMeasures?: number): string;
|
|
1501
1523
|
interface FieldEditorReference<U extends Blockly.Field> {
|
|
1502
1524
|
block: Blockly.Block;
|
|
1503
1525
|
field: string;
|
|
@@ -1511,5 +1533,6 @@ declare namespace pxtblockly {
|
|
|
1511
1533
|
function getAllFields<U extends Blockly.Field>(ws: Blockly.Workspace, predicate: (field: Blockly.Field) => boolean): FieldEditorReference<U>[];
|
|
1512
1534
|
function getAllReferencedTiles(workspace: Blockly.Workspace, excludeBlockID?: string): pxt.Tile[];
|
|
1513
1535
|
function getTemporaryAssets(workspace: Blockly.Workspace, type: pxt.AssetType): pxt.Asset[];
|
|
1536
|
+
function setMelodyEditorOpen(block: Blockly.Block, isOpen: boolean): void;
|
|
1514
1537
|
function workspaceToScreenCoordinates(ws: Blockly.WorkspaceSvg, wsCoordinates: Blockly.utils.Coordinate): Blockly.utils.Coordinate;
|
|
1515
1538
|
}
|