Skip to content

Commit 5239352

Browse files
authored
improve the monaco field editor experience for creating new assets and add animations (microsoft#10960)
1 parent 2eda505 commit 5239352

6 files changed

Lines changed: 108 additions & 8 deletions

File tree

‎pxteditor/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export * from "./monaco-fields/field_tilemap";
1212
export * from "./monaco-fields/field_musiceditor";
1313
export * from "./monaco-fields/field_soundEffect";
1414
export * from "./monaco-fields/field_sprite";
15+
export * from "./monaco-fields/field_animation";
1516
export * from "./monaco-fields/field_react";
1617

1718
export {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { MonacoReactFieldEditor } from "./field_react";
2+
import { registerMonacoFieldEditor } from "./monacoFieldEditor";
3+
4+
const fieldEditorId = "animation-editor";
5+
6+
export class MonacoAnimationEditor extends MonacoReactFieldEditor<pxt.Animation> {
7+
protected isPython: boolean;
8+
protected editing: pxt.Asset;
9+
10+
protected textToValue(text: string): pxt.Animation {
11+
this.isPython = text.indexOf("`") === -1
12+
13+
const match = pxt.parseAssetTSReference(text);
14+
if (match) {
15+
const { name: matchedName } = match;
16+
const name = matchedName.trim();
17+
const project = pxt.react.getTilemapProject();
18+
const asset = project.lookupAssetByName(pxt.AssetType.Animation, name);
19+
if (asset) {
20+
this.editing = asset;
21+
return asset;
22+
}
23+
else {
24+
const newAsset = project.createNewAnimation();
25+
26+
if (name && !project.isNameTaken(pxt.AssetType.Animation, name) && pxt.validateAssetName(name)) {
27+
newAsset.meta.displayName = name;
28+
}
29+
else {
30+
newAsset.meta.displayName = project.generateNewName(pxt.AssetType.Animation);
31+
}
32+
33+
this.editing = newAsset;
34+
35+
return newAsset;
36+
}
37+
}
38+
39+
return undefined;
40+
}
41+
42+
protected resultToText(result: pxt.Animation): string {
43+
const project = pxt.react.getTilemapProject();
44+
project.pushUndo();
45+
result = pxt.patchTemporaryAsset(this.editing, result, project) as pxt.Animation;
46+
result = project.updateAsset(result)
47+
return pxt.getTSReferenceForAsset(result, this.isPython);
48+
}
49+
50+
protected getFieldEditorId() {
51+
return fieldEditorId;
52+
}
53+
protected getOptions(): any {
54+
return {
55+
initWidth: 16,
56+
initHeight: 16,
57+
blocksInfo: this.host.blocksInfo()
58+
};
59+
}
60+
}
61+
62+
63+
const regexes = [
64+
// typescript
65+
"assets\\s*\\.\\s*animation\\s*`[a-zA-Z_\\s\\n]*`",
66+
67+
// python
68+
'assets\\s*\\.\\s*animation\\s*\\(\\s*"""[a-zA-Z_\\s\\n]*"""\\s*\\)'
69+
];
70+
71+
const searchString = regexes.map(r => `(?:${r})`).join("|");
72+
73+
export const animationEditorDefinition: pxt.editor.MonacoFieldEditorDefinition = {
74+
id: fieldEditorId,
75+
foldMatches: true,
76+
glyphCssClass: "sprite-editor-glyph sprite-focus-hover",
77+
heightInPixels: 510,
78+
matcher: {
79+
searchString: searchString,
80+
isRegex: true,
81+
matchCase: true,
82+
matchWholeWord: false
83+
},
84+
proto: MonacoAnimationEditor
85+
};
86+
87+
registerMonacoFieldEditor(fieldEditorId, animationEditorDefinition);

‎pxteditor/monaco-fields/field_musiceditor.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export class MonacoSongEditor extends MonacoReactFieldEditor<pxt.Song> {
3030
if (name && !project.isNameTaken(pxt.AssetType.Song, name) && pxt.validateAssetName(name)) {
3131
newAsset.meta.displayName = name;
3232
}
33+
else {
34+
newAsset.meta.displayName = project.generateNewName(pxt.AssetType.Song);
35+
}
3336

3437
this.editing = newAsset;
3538

‎pxteditor/monaco-fields/field_sprite.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export class MonacoSpriteEditor extends MonacoReactFieldEditor<pxt.ProjectImage>
3030
if (name && !project.isNameTaken(pxt.AssetType.Image, name) && pxt.validateAssetName(name)) {
3131
newAsset.meta.displayName = name;
3232
}
33+
else {
34+
newAsset.meta.displayName = project.generateNewName(pxt.AssetType.Image);
35+
}
3336

3437
this.editing = newAsset;
3538

‎pxtlib/tilemap.ts‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,18 @@ namespace pxt {
14011401
}
14021402
}
14031403

1404+
generateNewName(type: AssetType, name?: string) {
1405+
const defaultName = name || pxt.getDefaultAssetDisplayName(type);
1406+
let newName = defaultName;
1407+
let index = 0;
1408+
1409+
while (this.isNameTaken(type, newName)) {
1410+
newName = defaultName + (index++);
1411+
}
1412+
1413+
return newName;
1414+
}
1415+
14041416
protected generateNewIDInternal(type: AssetType, varPrefix: string, namespaceString?: string) {
14051417
varPrefix = varPrefix.replace(/\d+$/, "");
14061418
const prefix = namespaceString ? namespaceString + "." + varPrefix : varPrefix;
@@ -2010,7 +2022,7 @@ namespace pxt {
20102022
}
20112023

20122024
export function parseAssetTSReference(ts: string) {
2013-
const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap|song))|(tilemap))\s*(?:`|\(""")([^`"]+)(?:`|"""\))\s*$/m.exec(ts);
2025+
const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap|song))|(tilemap))\s*(?:`|\(""")([^`"]*)(?:`|"""\))\s*$/m.exec(ts);
20142026

20152027
if (match) {
20162028
const type = match[1] || match[2];

‎webapp/src/assetEditor.tsx‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,7 @@ export class AssetEditor extends React.Component<{}, AssetEditorState> {
377377
protected getEmptyAsset(type: pxt.AssetType, displayName?: string): pxt.Asset {
378378
const project = pxt.react.getTilemapProject();
379379

380-
const defaultName = displayName || pxt.getDefaultAssetDisplayName(type);
381-
let newName = defaultName;
382-
let index = 0;
383-
384-
while (project.isNameTaken(type, newName)) {
385-
newName = defaultName + (index++);
386-
}
380+
const newName = project.generateNewName(type, displayName);
387381

388382
const asset = { type, id: "", internalID: 0, meta: { displayName: newName } } as pxt.Asset;
389383
switch (type) {

0 commit comments

Comments
 (0)