From fa1ef5285c53b8849b3b54e7b3eea8734f68978a Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 23 May 2023 06:58:01 -0400 Subject: [PATCH 01/72] Update version. --- source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts index d2ba894aa..fc7ffb038 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts @@ -322,7 +322,7 @@ namespace phasereditor2d.ide { /* program entry point */ - export const VER = "3.61.0"; + export const VER = "3.61.1"; async function main() { From e3ca1064c6b25313d43f91a8044e146f3852fe72 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 23 May 2023 09:47:35 -0400 Subject: [PATCH 02/72] Fixes hit area for containers. #284 --- design/logo-icons/gumroad-logo.png | Bin 0 -> 29732 bytes .../hitArea/PolygonHitAreaToolItem.ts | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 design/logo-icons/gumroad-logo.png diff --git a/design/logo-icons/gumroad-logo.png b/design/logo-icons/gumroad-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aa4b4555caa62ef3d3fdaf80ff801da880757f2a GIT binary patch literal 29732 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 QivR!s07*qoM6N<$f|FAm7XSbN literal 0 HcmV?d00001 diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaToolItem.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaToolItem.ts index 6b55224ce..6037edd90 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaToolItem.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaToolItem.ts @@ -219,7 +219,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { const obj = comp.getObject() as Sprite; - const { displayOriginX, displayOriginY } = obj.getEditorSupport().computeDisplayOrigin(); + const { displayOriginX, displayOriginY } = this.getDisplayOrigin(obj); const tx = obj.getWorldTransformMatrix(); @@ -366,7 +366,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { sprite.getWorldTransformMatrix().applyInverse(newPoint.x, newPoint.y, newPoint); - const {displayOriginX, displayOriginY} = sprite.getEditorSupport().computeDisplayOrigin(); + let { displayOriginX, displayOriginY } = this.getDisplayOrigin(sprite); point.x = newPoint.x + displayOriginX; point.y = newPoint.y + displayOriginY; @@ -376,6 +376,16 @@ namespace phasereditor2d.scene.ui.sceneobjects { args.editor.updateInspectorViewSection(PolygonHitAreaSection.ID); } + private getDisplayOrigin(sprite: ISceneGameObject) { + + if (sprite instanceof Container) { + + return { displayOriginX: 0, displayOriginY: 0 }; + } + + return sprite.getEditorSupport().computeDisplayOrigin(); + } + onStopDrag(args: editor.tools.ISceneToolDragEventArgs): void { this._newPoint = undefined; From e3a76876243f7225344d242cf73d53af1ce6030c Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 23 May 2023 09:57:28 -0400 Subject: [PATCH 03/72] #284 Fixes initial values for hit area on containers. --- .../ui/sceneobjects/hitArea/BaseHitAreaComponent.ts | 10 ++++++++-- .../ui/sceneobjects/hitArea/CircleHitAreaComponent.ts | 6 +++--- .../ui/sceneobjects/hitArea/EllipseHitAreaComponent.ts | 6 +++--- .../hitArea/PixelPerfectHitAreaComponent.ts | 2 +- .../ui/sceneobjects/hitArea/PolygonHitAreaComponent.ts | 6 +++--- .../sceneobjects/hitArea/RectangleHitAreaComponent.ts | 6 +++--- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts index 368d775d2..d105205c4 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts @@ -35,7 +35,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { super.readJSON(ser); } - protected abstract _setDefaultValues(width: number, height: number): void; + protected abstract _setDefaultValues(x: number, y: number, width: number, height: number): void; setDefaultValues() { @@ -43,6 +43,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { const objES = this.getEditorSupport(); let width = 0, height = 0; + let x = 0, y = 0; let [widthProp, heightProp] = objES.getSizeProperties(); @@ -60,13 +61,18 @@ namespace phasereditor2d.scene.ui.sceneobjects { width = b.width; height = b.height; + const origin = c.getEditorSupport().computeDisplayOrigin(); + + x = -origin.displayOriginX; + y = -origin.displayOriginY; + } else if (obj.width && obj.height) { width = obj.width; height = obj.height; } - this._setDefaultValues(width, height); + this._setDefaultValues(x, y, width, height); } buildSetObjectPropertiesCodeDOM(args: ISetObjectPropertiesCodeDOMArgs): void { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/CircleHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/CircleHitAreaComponent.ts index 1121d070f..2d5091c57 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/CircleHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/CircleHitAreaComponent.ts @@ -35,10 +35,10 @@ namespace phasereditor2d.scene.ui.sceneobjects { return comp; } - protected _setDefaultValues(width: number, height: number): void { + protected _setDefaultValues(x:number, y: number, width: number, height: number): void { - this.x = width / 2; - this.y = height / 2; + this.x = x + width / 2; + this.y = y + height / 2; this.radius = Math.min(width, height) / 2; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/EllipseHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/EllipseHitAreaComponent.ts index e8d5d0b08..c6c00369f 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/EllipseHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/EllipseHitAreaComponent.ts @@ -44,10 +44,10 @@ namespace phasereditor2d.scene.ui.sceneobjects { return comp; } - protected _setDefaultValues(width: number, height: number): void { + protected _setDefaultValues(x: number, y: number, width: number, height: number): void { - this.x = width / 2; - this.y = height / 2; + this.x = x + width / 2; + this.y = y + height / 2; this.width = width; this.height = height; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PixelPerfectHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PixelPerfectHitAreaComponent.ts index 1cbe18fb6..ac359cc05 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PixelPerfectHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PixelPerfectHitAreaComponent.ts @@ -23,7 +23,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { return comp; } - protected _setDefaultValues(width: number, height: number): void { + protected _setDefaultValues(x:number, y: number, width: number, height: number): void { // nothing } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaComponent.ts index 6b79d76f1..fb772857b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/PolygonHitAreaComponent.ts @@ -5,7 +5,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { export class PolygonHitAreaComponent extends BaseHitAreaComponent { static points = HitAreaProperty(PolygonHitAreaComponent, "points", "Points", "The polygon's points, in a string format `X1 Y1 Y2 X2...`", ""); - + public points: string; constructor(obj: ISceneGameObject) { @@ -42,9 +42,9 @@ namespace phasereditor2d.scene.ui.sceneobjects { return comp; } - protected _setDefaultValues(w: number, h: number): void { + protected _setDefaultValues(x: number, y: number, w: number, h: number): void { - this.points = `0 ${h * 0.25} ${w/2} 0 ${w} ${h * 0.25} ${w} ${h} 0 ${h}`; + this.points = `${x} ${y + h * 0.25} ${x + w / 2} ${y} ${x + w} ${y + h * 0.25} ${x + w} ${y + h} ${x} ${y + h}`; } protected override buildSetInteractiveCodeCOM( diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/RectangleHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/RectangleHitAreaComponent.ts index f10ddb978..2f4877039 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/RectangleHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/RectangleHitAreaComponent.ts @@ -41,10 +41,10 @@ namespace phasereditor2d.scene.ui.sceneobjects { return comp; } - protected _setDefaultValues(width: number, height: number): void { + protected _setDefaultValues(x:number, y: number, width: number, height: number): void { - this.x = 0; - this.y = 0; + this.x = x; + this.y = y; this.width = width; this.height = height; } From bfd15a5f161ef0fcd67966fd4a4da49fb3e5eb01 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 23 May 2023 10:18:11 -0400 Subject: [PATCH 04/72] Updates changelog. --- CHANGELOG.MD | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index b3b0b9f04..6bb79d8d6 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,5 +1,9 @@ # Change Log +## v3.61.1-dev + +* [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. + ## v3.61.0 - May 18, 2023 * Checks if a scene file was generated by a newer and incompatible version of the editor. From 60273ed6b788918d7a683ff2b0cc2fd287be454d Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 15:11:43 -0400 Subject: [PATCH 05/72] Adds the Add Property command. --- .vscode/settings.json | 2 +- .../viewers/EmptyCellRendererProvider.ts | 1 + .../phasereditor2d.ide/src/IDEPlugin.ts | 1 + .../phasereditor2d.scene/src/ScenePlugin.ts | 15 +++-- .../src/ui/dialogs/AddPrefabPropertyDialog.ts | 61 +++++++++++++++++++ .../src/ui/editor/SceneEditorMenuCreator.ts | 2 + .../ui/editor/commands/SceneEditorCommands.ts | 41 +++++++++++++ .../properties/PrefabPropertiesSection.ts | 2 +- .../properties/SingleUserPropertySection.ts | 8 +-- .../properties/UserPropertiesSection.ts | 6 +- .../usercomponent/UserComponentSection.ts | 2 +- .../userProperties/UserProperty.ts | 2 +- 12 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index ff45a1acc..e4084b21b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "workbench.colorTheme": "Solarized Dark" + "workbench.colorTheme": "GitHub Dark" } \ No newline at end of file diff --git a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts index dc8fb7623..8bc169a11 100644 --- a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts +++ b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts @@ -18,6 +18,7 @@ namespace colibri.ui.controls.viewers { } preload(obj: any): Promise { + return Controls.resolveNothingLoaded(); } } diff --git a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts index fc7ffb038..8a9597578 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts @@ -265,6 +265,7 @@ namespace phasereditor2d.ide { } isOpeningProject() { + return this._openingProject; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index 7f42def3e..a40b3af9d 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -469,10 +469,17 @@ namespace phasereditor2d.scene { return settings; } - createUserPropertyTypes() { + private _userPropertyTypes: ui.sceneobjects.UserPropertyType[]; + + getUserPropertyTypes() { + + if (this._userPropertyTypes) { + + return this._userPropertyTypes; + } // TODO: we should do this via extension - return [ + return this._userPropertyTypes = [ new ui.sceneobjects.NumberPropertyType(), new ui.sceneobjects.StringPropertyType(), new ui.sceneobjects.BooleanPropertyType(), @@ -489,9 +496,9 @@ namespace phasereditor2d.scene { ]; } - createUserPropertyType(typeId: string) { + getUserPropertyType(typeId: string) { - return this.createUserPropertyTypes().find(t => t.getId() === typeId); + return this.getUserPropertyTypes().find(t => t.getId() === typeId); } getPrefabColor() { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts new file mode 100644 index 000000000..20a219762 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts @@ -0,0 +1,61 @@ +namespace phasereditor2d.scene.ui.dialogs { + + import controls = colibri.ui.controls; + + export class AddPrefabPropertyDialog extends controls.dialogs.ViewerDialog { + + constructor() { + super(new UserPropertyTypesViewer(), false); + + this.setSize(300, 400, true); + } + + create(hideParentDialog?: boolean): void { + + super.create(hideParentDialog); + + this.setTitle("Add Prefab Property"); + + this.enableButtonOnlyWhenOneElementIsSelected(this.addOpenButton("Add Property", sel => { + + this.addProperty(sel[0] as sceneobjects.UserPropertyType); + })); + + this.addCancelButton(); + } + + private addProperty(propType: sceneobjects.UserPropertyType) { + + const editor = colibri.Platform.getWorkbench().getActiveEditor() as ui.editor.SceneEditor; + + ui.editor.properties.PrefabPropertySection.runPropertiesOperation(editor, (props) => { + + const prop = props.createProperty(propType); + + props.add(prop); + + editor.setSelection([prop]); + }); + } + } + + class UserPropertyTypesViewer extends controls.viewers.TreeViewer { + + constructor() { + super("phasereditor2d.scene.ui.dialogs.UserPropertyTypesViewer"); + + this.setLabelProvider(new UserPropertyTypeLabelProvider()); + this.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); + this.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider()); + this.setInput(ScenePlugin.getInstance().getUserPropertyTypes()); + } + } + + class UserPropertyTypeLabelProvider implements controls.viewers.ILabelProvider { + + getLabel(obj: ui.sceneobjects.UserPropertyType): string { + + return `${obj.getName()} Property`; + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts index 4c4b68a56..83a6e41b4 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts @@ -317,6 +317,8 @@ namespace phasereditor2d.scene.ui.editor { menu.addCommand(commands.CMD_OPEN_PREFAB); menu.addCommand(commands.CMD_CREATE_PREFAB_WITH_OBJECT); + menu.addSeparator(); + menu.addCommand(commands.CMD_ADD_PREFAB_PROPERTY); return menu; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index eb27e94de..bd1f48951 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -60,6 +60,7 @@ namespace phasereditor2d.scene.ui.editor.commands { export const CMD_OPEN_ADD_SCRIPT_DIALOG = "phasereditor2d.scene.ui.editor.commands.OpenAddScriptDialog"; export const CMD_PREVIEW_SCENE = "phasereditor2d.scene.ui.editor.commands.PreviewScene"; export const CMD_EDIT_HIT_AREA = "phasereditor2d.scene.ui.editor.commands.ResizeHitArea"; + export const CMD_ADD_PREFAB_PROPERTY = "phasereditor2d.scene.ui.editor.commands.AddPrefabProperty"; function isSceneScope(args: colibri.ui.ide.commands.HandlerArgs) { @@ -153,6 +154,46 @@ namespace phasereditor2d.scene.ui.editor.commands { this.registerArcadeCommands(manager); this.registerScriptNodeCommands(manager); + + this.registerPrefabCommands(manager); + } + + private static registerPrefabCommands(manager: colibri.ui.ide.commands.CommandManager) { + + manager.add({ + command: { + id: CMD_ADD_PREFAB_PROPERTY, + name: "Add Prefab Property", + category: CAT_SCENE_EDITOR, + tooltip: "Add a new property to the current prefab" + }, + handler: { + testFunc: args => { + + if (isSceneScope(args)) { + + const editor = args.activeEditor as SceneEditor; + + return editor.getScene().isPrefabSceneType(); + } + + return false; + }, + executeFunc: args => { + + const editor = args.activeEditor as SceneEditor; + + const dialog = new ui.dialogs.AddPrefabPropertyDialog(); + dialog.create(); + + // ui.editor.properties.PrefabPropertySection.runPropertiesOperation(editor, () => { + + // // TODO: show the Add Property dialog + + // }, true); + } + } + }) } private static registerScriptNodeCommands(manager: colibri.ui.ide.commands.CommandManager) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts index 2dbb0a616..4e46a7a7f 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts @@ -23,7 +23,7 @@ namespace phasereditor2d.scene.ui.editor.properties { this.getEditor().setSelection([obj]); }; - SingleUserPropertySection.createAddComponentButton(comp, this, action => this.runOperation(action), selector); + SingleUserPropertySection.createAddProprtyButton(comp, this, action => this.runOperation(action), selector); } runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection = true) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts index f4d2c1c7e..c653e3d7a 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts @@ -15,21 +15,21 @@ namespace phasereditor2d.scene.ui.editor.properties { protected abstract runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean); - static createAddComponentButton( + static createAddProprtyButton( comp: HTMLDivElement, formBuilder: colibri.ui.controls.properties.FormBuilder, runOperation: ( action: TUserPropertiesAction) => void, selector: (obj:any) => void) { - const propTypes = ScenePlugin.getInstance().createUserPropertyTypes(); + const propTypes = ScenePlugin.getInstance().getUserPropertyTypes(); const buttonElement = formBuilder.createMenuButton(comp, "Add Property", () => propTypes.map(t => ({ name: t.getName() + " Property", value: t.getId() })), (typeId: string) => { - const newType = ScenePlugin.getInstance().createUserPropertyType(typeId); + const newType = ScenePlugin.getInstance().getUserPropertyType(typeId); runOperation(userProps => { @@ -267,7 +267,7 @@ namespace phasereditor2d.scene.ui.editor.properties { const menu = new controls.Menu("Change Type"); - const propTypes = ScenePlugin.getInstance().createUserPropertyTypes(); + const propTypes = ScenePlugin.getInstance().getUserPropertyTypes(); for (const propType of propTypes) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts index df18254d9..faa352e89 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts @@ -32,14 +32,14 @@ namespace phasereditor2d.scene.ui.editor.properties { this._propArea = this.createGridElement(comp, 2); comp.appendChild(this._propArea); - const propTypes = ScenePlugin.getInstance().createUserPropertyTypes(); + const propTypes = ScenePlugin.getInstance().getUserPropertyTypes(); const btn = this.createMenuButton(comp, "Add Property", () => propTypes.map(t => ({ name: t.getName() + " Property", value: t.getId() })), (typeId: string) => { - const newType = ScenePlugin.getInstance().createUserPropertyType(typeId); + const newType = ScenePlugin.getInstance().getUserPropertyType(typeId); this.runOperation(userProps => { @@ -259,7 +259,7 @@ namespace phasereditor2d.scene.ui.editor.properties { const menu = new controls.Menu("Change Type"); - const propTypes = ScenePlugin.getInstance().createUserPropertyTypes(); + const propTypes = ScenePlugin.getInstance().getUserPropertyTypes(); for (const propType of propTypes) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentSection.ts index ec8571170..c8487879b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentSection.ts @@ -61,7 +61,7 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { }; const { buttonElement } = editor.properties.SingleUserPropertySection - .createAddComponentButton(comp, this, op, selector); + .createAddProprtyButton(comp, this, op, selector); buttonElement.style.marginTop = "10px"; buttonElement.style.width = "100%"; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts index 7af24d578..6f57726cf 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts @@ -91,7 +91,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { const typeData = data.type; const typeId = typeData.id; - const propType = ScenePlugin.getInstance().createUserPropertyType(typeId); + const propType = ScenePlugin.getInstance().getUserPropertyType(typeId); propType.readJSON(typeData); this._info = { From ded7e7d18723ed41fe1bf2889180518290d8f9c1 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 15:27:44 -0400 Subject: [PATCH 06/72] The Add Property button now opens the dialog. --- .../AbstractAddPrefabPropertyDialog.ts | 49 +++++++++++++++++++ .../src/ui/dialogs/AddPrefabPropertyDialog.ts | 48 ++---------------- .../properties/SingleUserPropertySection.ts | 28 ++++++----- 3 files changed, 69 insertions(+), 56 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts new file mode 100644 index 000000000..ef41d82e4 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts @@ -0,0 +1,49 @@ +namespace phasereditor2d.scene.ui.dialogs { + + import controls = colibri.ui.controls; + + export abstract class AbstractAddPrefabPropertyDialog extends controls.dialogs.ViewerDialog { + + constructor() { + super(new UserPropertyTypesViewer(), false); + + this.setSize(300, 400, true); + } + + create(hideParentDialog?: boolean): void { + + super.create(hideParentDialog); + + this.setTitle("Add Prefab Property"); + + this.enableButtonOnlyWhenOneElementIsSelected(this.addOpenButton("Add Property", sel => { + + this.addProperty(sel[0] as sceneobjects.UserPropertyType); + })); + + this.addCancelButton(); + } + + protected abstract addProperty(propType: sceneobjects.UserPropertyType): void; + } + + class UserPropertyTypesViewer extends controls.viewers.TreeViewer { + + constructor() { + super("phasereditor2d.scene.ui.dialogs.UserPropertyTypesViewer"); + + this.setLabelProvider(new UserPropertyTypeLabelProvider()); + this.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); + this.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider()); + this.setInput(ScenePlugin.getInstance().getUserPropertyTypes()); + } + } + + class UserPropertyTypeLabelProvider implements controls.viewers.ILabelProvider { + + getLabel(obj: ui.sceneobjects.UserPropertyType): string { + + return `${obj.getName()} Property`; + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts index 20a219762..ddff05550 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts @@ -1,30 +1,10 @@ -namespace phasereditor2d.scene.ui.dialogs { - - import controls = colibri.ui.controls; - - export class AddPrefabPropertyDialog extends controls.dialogs.ViewerDialog { - - constructor() { - super(new UserPropertyTypesViewer(), false); - - this.setSize(300, 400, true); - } +/// - create(hideParentDialog?: boolean): void { - - super.create(hideParentDialog); - - this.setTitle("Add Prefab Property"); - - this.enableButtonOnlyWhenOneElementIsSelected(this.addOpenButton("Add Property", sel => { +namespace phasereditor2d.scene.ui.dialogs { - this.addProperty(sel[0] as sceneobjects.UserPropertyType); - })); + export class AddPrefabPropertyDialog extends AbstractAddPrefabPropertyDialog { - this.addCancelButton(); - } - - private addProperty(propType: sceneobjects.UserPropertyType) { + protected override addProperty(propType: sceneobjects.UserPropertyType) { const editor = colibri.Platform.getWorkbench().getActiveEditor() as ui.editor.SceneEditor; @@ -38,24 +18,4 @@ namespace phasereditor2d.scene.ui.dialogs { }); } } - - class UserPropertyTypesViewer extends controls.viewers.TreeViewer { - - constructor() { - super("phasereditor2d.scene.ui.dialogs.UserPropertyTypesViewer"); - - this.setLabelProvider(new UserPropertyTypeLabelProvider()); - this.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); - this.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider()); - this.setInput(ScenePlugin.getInstance().getUserPropertyTypes()); - } - } - - class UserPropertyTypeLabelProvider implements controls.viewers.ILabelProvider { - - getLabel(obj: ui.sceneobjects.UserPropertyType): string { - - return `${obj.getName()} Property`; - } - } } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts index c653e3d7a..5d26b6fc8 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts @@ -20,24 +20,28 @@ namespace phasereditor2d.scene.ui.editor.properties { formBuilder: colibri.ui.controls.properties.FormBuilder, runOperation: ( action: TUserPropertiesAction) => void, - selector: (obj:any) => void) { + selector: (obj: any) => void) { const propTypes = ScenePlugin.getInstance().getUserPropertyTypes(); - const buttonElement = formBuilder.createMenuButton(comp, "Add Property", () => propTypes.map(t => ({ - name: t.getName() + " Property", - value: t.getId() - })), (typeId: string) => { + const buttonElement = formBuilder.createButton(comp, "Add Property", () => { - const newType = ScenePlugin.getInstance().getUserPropertyType(typeId); + class Dlg extends ui.dialogs.AbstractAddPrefabPropertyDialog { - runOperation(userProps => { + protected addProperty(propType: sceneobjects.UserPropertyType): void { - const prop = userProps.createProperty(newType); - userProps.add(prop); + runOperation(userProps => { - selector(prop); - }); + const prop = userProps.createProperty(propType); + userProps.add(prop); + + selector(prop); + }); + } + } + + const dlg = new Dlg(); + dlg.create(); }); return { buttonElement }; @@ -102,7 +106,7 @@ namespace phasereditor2d.scene.ui.editor.properties { this.runOperation(userProps => { userProps.deleteProperty(prop.getName()); - + }, true); } }); From 44acb74b4826a5f1580ad56f4a1c776181de40ed Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 16:45:18 -0400 Subject: [PATCH 07/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 6bb79d8d6..86048afda 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -3,6 +3,7 @@ ## v3.61.1-dev * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. +* A new Add Prefab Property command that shows a dialog. ## v3.61.0 - May 18, 2023 From 65892f25a8fdbacfc192fff8a17b1c721acf1310 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 18:28:03 -0400 Subject: [PATCH 08/72] Replaces the Object Depth commands for the Edit move commands. --- .../src/ui/editor/SceneEditorMenuCreator.ts | 23 ++-- .../ui/editor/commands/SceneEditorCommands.ts | 100 +++++++++++++----- 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts index 83a6e41b4..72ebd0e05 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts @@ -39,8 +39,6 @@ namespace phasereditor2d.scene.ui.editor { menu.addMenu(this.createParentMenu()); - menu.addMenu(this.createDepthMenu()); - menu.addMenu(this.createListMenu()); menu.addSeparator(); @@ -170,20 +168,6 @@ namespace phasereditor2d.scene.ui.editor { return menu; } - private createDepthMenu(): controls.Menu { - - const menu = new controls.Menu("Depth"); - - for (const move of ["Up", "Down", "Top", "Bottom"]) { - - const id = "phasereditor2d.scene.ui.editor.commands.Depth" + move; - - menu.addCommand(id); - } - - return menu; - } - private createListMenu(): controls.Menu { const menu = new controls.Menu("Object List"); @@ -213,6 +197,13 @@ namespace phasereditor2d.scene.ui.editor { menu.addCommand(commands.CMD_PASTE_IN_PLACE); menu.addCommand(colibri.ui.ide.actions.CMD_DELETE); + menu.addSeparator(); + + menu.addCommand(commands.CMD_SORT_OBJ_UP); + menu.addCommand(commands.CMD_SORT_OBJ_DOWN); + menu.addCommand(commands.CMD_SORT_OBJ_TOP); + menu.addCommand(commands.CMD_SORT_OBJ_BOTTOM); + return menu; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index bd1f48951..6e74de7c0 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -61,6 +61,10 @@ namespace phasereditor2d.scene.ui.editor.commands { export const CMD_PREVIEW_SCENE = "phasereditor2d.scene.ui.editor.commands.PreviewScene"; export const CMD_EDIT_HIT_AREA = "phasereditor2d.scene.ui.editor.commands.ResizeHitArea"; export const CMD_ADD_PREFAB_PROPERTY = "phasereditor2d.scene.ui.editor.commands.AddPrefabProperty"; + export const CMD_SORT_OBJ_UP = "phasereditor2d.scene.ui.editor.commands.SortObjectUp"; + export const CMD_SORT_OBJ_DOWN = "phasereditor2d.scene.ui.editor.commands.SortObjectDown"; + export const CMD_SORT_OBJ_TOP = "phasereditor2d.scene.ui.editor.commands.SortObjectTop"; + export const CMD_SORT_OBJ_BOTTOM = "phasereditor2d.scene.ui.editor.commands.SortObjectBottom"; function isSceneScope(args: colibri.ui.ide.commands.HandlerArgs) { @@ -186,11 +190,11 @@ namespace phasereditor2d.scene.ui.editor.commands { const dialog = new ui.dialogs.AddPrefabPropertyDialog(); dialog.create(); - // ui.editor.properties.PrefabPropertySection.runPropertiesOperation(editor, () => { + // ui.editor.properties.PrefabPropertySection.runPropertiesOperation(editor, () => { - // // TODO: show the Add Property dialog + // // TODO: show the Add Property dialog - // }, true); + // }, true); } } }) @@ -1079,6 +1083,56 @@ namespace phasereditor2d.scene.ui.editor.commands { args => args.activeEditor.getUndoManager() .add(new undo.DeleteOperation(args.activeEditor as SceneEditor)) ); + + // sort + + manager.add({ + command: { + id: CMD_SORT_OBJ_UP, + name: "Move Up", + tooltip: "Move up object in the list.", + category: CAT_SCENE_EDITOR + }, + keys: { + key: "PageUp" + } + }); + + manager.add({ + command: { + id: CMD_SORT_OBJ_DOWN, + name: "Move Down", + tooltip: "Move down object in the list.", + category: CAT_SCENE_EDITOR + }, + keys: { + key: "PageDown" + } + }); + + manager.add({ + command: { + id: CMD_SORT_OBJ_TOP, + name: "Move Top", + tooltip: "Move top object in the list.", + category: CAT_SCENE_EDITOR + }, + keys: { + key: "Home" + } + }); + + manager.add({ + command: { + id: CMD_SORT_OBJ_BOTTOM, + name: "Move Bottom", + tooltip: "Move bottom object in the list.", + category: CAT_SCENE_EDITOR + }, + keys: { + key: "End" + } + }); } private static registerMoveObjectCommands(manager: colibri.ui.ide.commands.CommandManager) { @@ -2028,34 +2082,26 @@ namespace phasereditor2d.scene.ui.editor.commands { private static registerDepthCommands(manager: colibri.ui.ide.commands.CommandManager) { - const moves: [undo.DepthMove, string][] = [["Up", "PageUp"], ["Down", "PageDown"], ["Top", "Home"], ["Bottom", "End"]]; + const moves: [undo.DepthMove, string][] = [ + ["Up", CMD_SORT_OBJ_UP], + ["Down", CMD_SORT_OBJ_DOWN], + ["Top", CMD_SORT_OBJ_TOP], + ["Bottom", CMD_SORT_OBJ_BOTTOM] + ]; for (const tuple of moves) { const move = tuple[0]; - const key = tuple[1]; - - manager.add({ - - command: { - id: "phasereditor2d.scene.ui.editor.commands.Depth" + move, - name: "Move Object Depth " + move, - category: CAT_SCENE_EDITOR, - tooltip: "Move the object in its container to " + move + "." - }, - - handler: { - testFunc: args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 - && undo.DepthOperation.allow(args.activeEditor as any, move), - - executeFunc: args => args.activeEditor.getUndoManager().add( - new undo.DepthOperation(args.activeEditor as editor.SceneEditor, move)) - }, - - keys: { - key - } - }); + const cmd = tuple[1]; + + manager.addHandlerHelper(cmd, + // testFunc + args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 + && undo.DepthOperation.allow(args.activeEditor as any, move), + // execFunc + args => args.activeEditor.getUndoManager().add( + new undo.DepthOperation(args.activeEditor as editor.SceneEditor, move) + )); } } From 97232cb24398ee3b9dfe2b9bcfdfcecb3f3ba16f Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 18:28:21 -0400 Subject: [PATCH 09/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 86048afda..ba381cf16 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,7 @@ * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. * A new Add Prefab Property command that shows a dialog. +* Replaces the Object Depth commands for the Edit move commands. ## v3.61.0 - May 18, 2023 From a08c39d1fce5f1813a0a1f597853b92ee5e13ccf Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 18:36:51 -0400 Subject: [PATCH 10/72] Replaces the Object List depth commands by the Editor move commands. --- .../src/ui/editor/SceneEditorMenuCreator.ts | 16 -------- .../ui/editor/commands/SceneEditorCommands.ts | 38 ++++++++----------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts index 72ebd0e05..717a32951 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts @@ -39,8 +39,6 @@ namespace phasereditor2d.scene.ui.editor { menu.addMenu(this.createParentMenu()); - menu.addMenu(this.createListMenu()); - menu.addSeparator(); menu.addMenu(this.createSnappingMenu()); @@ -168,20 +166,6 @@ namespace phasereditor2d.scene.ui.editor { return menu; } - private createListMenu(): controls.Menu { - - const menu = new controls.Menu("Object List"); - - for (const move of ["Up", "Down", "Top", "Bottom"]) { - - const id = "phasereditor2d.scene.ui.editor.commands.ListOrder" + move; - - menu.addCommand(id); - } - - return menu; - } - private createEditMenu() { const menu = new controls.Menu("Edit"); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index 6e74de7c0..08063fa61 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -2109,34 +2109,26 @@ namespace phasereditor2d.scene.ui.editor.commands { // order commands - const moves: [undo.DepthMove, string][] = [["Up", "PageUp"], ["Down", "PageDown"], ["Top", "Home"], ["Bottom", "End"]]; + const moves: [undo.DepthMove, string][] = [ + ["Up", CMD_SORT_OBJ_UP], + ["Down", CMD_SORT_OBJ_DOWN], + ["Top", CMD_SORT_OBJ_TOP], + ["Bottom", CMD_SORT_OBJ_BOTTOM] + ]; for (const tuple of moves) { const move = tuple[0]; - const key = tuple[1]; - - manager.add({ - - command: { - id: "phasereditor2d.scene.ui.editor.commands.ListOrder" + move, - name: "Move " + move, - category: CAT_SCENE_EDITOR, - tooltip: "Move the object in its list to " + move + "." - }, - - handler: { - testFunc: args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 - && sceneobjects.ListOrderOperation.allow(args.activeEditor as any, move), - - executeFunc: args => args.activeEditor.getUndoManager().add( - new sceneobjects.ListOrderOperation(args.activeEditor as editor.SceneEditor, move)) - }, + const cmd = tuple[1]; - keys: { - key - } - }); + manager.addHandlerHelper(cmd, + // testFunc + args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 + && sceneobjects.ListOrderOperation.allow(args.activeEditor as any, move), + // execFunc + args => args.activeEditor.getUndoManager().add( + new sceneobjects.ListOrderOperation(args.activeEditor as editor.SceneEditor, move)) + ); } } From b7510d15a1f4b746e96b07d2820b72c4948a9833 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 18:37:11 -0400 Subject: [PATCH 11/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index ba381cf16..6876cfaea 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -5,6 +5,7 @@ * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. * A new Add Prefab Property command that shows a dialog. * Replaces the Object Depth commands for the Edit move commands. +* Replaces the Object List sort commands by the Editor move commands. ## v3.61.0 - May 18, 2023 From b5a431393c150c30469c7f269f644c93692d991b Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 21:25:03 -0400 Subject: [PATCH 12/72] Allows change prefab properties with the Edit move components. Removes the Move menu items from the Prefab Properties section. --- .../src/ui/dialogs/AddPrefabPropertyDialog.ts | 2 +- .../ui/editor/commands/SceneEditorCommands.ts | 31 ++++++ .../ChangePrefabPropertiesOperation.ts | 23 ++++ .../properties/PrefabPropertiesSection.ts | 2 +- .../properties/PrefabPropertyOrderAction.ts | 105 ++++++++++++++++++ .../properties/PrefabPropertySection.ts | 25 +---- .../properties/SingleUserPropertySection.ts | 42 ------- 7 files changed, 162 insertions(+), 68 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts index ddff05550..6c6a3c902 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AddPrefabPropertyDialog.ts @@ -8,7 +8,7 @@ namespace phasereditor2d.scene.ui.dialogs { const editor = colibri.Platform.getWorkbench().getActiveEditor() as ui.editor.SceneEditor; - ui.editor.properties.PrefabPropertySection.runPropertiesOperation(editor, (props) => { + ui.editor.properties.ChangePrefabPropertiesOperation.runPropertiesOperation(editor, (props) => { const prop = props.createProperty(propType); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index 08063fa61..e2f3d6ecc 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -160,6 +160,8 @@ namespace phasereditor2d.scene.ui.editor.commands { this.registerScriptNodeCommands(manager); this.registerPrefabCommands(manager); + + this.registerPropertiesCommands(manager); } private static registerPrefabCommands(manager: colibri.ui.ide.commands.CommandManager) { @@ -2105,6 +2107,35 @@ namespace phasereditor2d.scene.ui.editor.commands { } } + private static registerPropertiesCommands(manager: colibri.ui.ide.commands.CommandManager) { + + // order commands + + const moves: [undo.DepthMove, string][] = [ + ["Up", CMD_SORT_OBJ_UP], + ["Down", CMD_SORT_OBJ_DOWN], + ["Top", CMD_SORT_OBJ_TOP], + ["Bottom", CMD_SORT_OBJ_BOTTOM] + ]; + + for (const tuple of moves) { + + const move = tuple[0]; + const cmd = tuple[1]; + + manager.addHandlerHelper(cmd, + // testFunc + args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 + && properties.PrefabPropertyOrderAction.allow(args.activeEditor as any, move), + // execFunc + args => properties.ChangePrefabPropertiesOperation.runPropertiesOperation(args.activeEditor as SceneEditor, props => { + + properties.PrefabPropertyOrderAction.execute(args.activeEditor as SceneEditor, move); + }) + ); + } + } + private static registerListCommands(manager: colibri.ui.ide.commands.CommandManager) { // order commands diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts index e8206a689..e28e9f1c0 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts @@ -22,6 +22,29 @@ namespace phasereditor2d.scene.ui.editor.properties { return data; } + static runPropertiesOperation(editor: SceneEditor, action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { + + const scene = editor.getScene(); + + const before = this.snapshot(editor); + + action(scene.getPrefabUserProperties()); + + const after = this.snapshot(editor); + + editor.getUndoManager() + .add(new ChangePrefabPropertiesOperation(editor, before, after)); + + editor.setDirty(true); + + editor.refreshOutline(); + + if (updateSelection) { + + editor.getSelectionManager().refreshSelection(); + } + } + private load(data: any) { const editor = this.getEditor(); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts index 4e46a7a7f..aa0527f5e 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts @@ -28,7 +28,7 @@ namespace phasereditor2d.scene.ui.editor.properties { runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection = true) { - PrefabPropertySection.runPropertiesOperation(this.getEditor(), action, updateSelection); + ui.editor.properties.ChangePrefabPropertiesOperation.runPropertiesOperation(this.getEditor(), action, updateSelection); } canEdit(obj: any, n: number): boolean { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts new file mode 100644 index 000000000..f0e8f091a --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts @@ -0,0 +1,105 @@ +namespace phasereditor2d.scene.ui.editor.properties { + + export class PrefabPropertyOrderAction { + + static allow(editor: SceneEditor, move: ui.editor.undo.DepthMove) { + + const sel: ui.sceneobjects.UserProperty[] = editor.getSelection(); + + if (sel.length === 0) { + + return false; + } + + for (const prop of sel) { + + if (!(prop instanceof ui.sceneobjects.UserProperty)) { + + return false; + } + } + + const siblings = sel[0].getAllProperties().getProperties(); + + for (const prop of sel) { + + const index = siblings.indexOf(prop); + + const len = siblings.length; + + if (move === "Bottom" || move === "Down") { + + if (index === len - 1) { + + return false; + } + + } else { // Top || Up + + if (index === 0) { + + return false; + } + } + } + + return true; + } + + static execute(editor: SceneEditor, depthMove: undo.DepthMove): void { + + const sel = editor.getSelection() as any as sceneobjects.UserProperty[]; + + switch (depthMove) { + + case "Bottom": + + for (const prop of sel) { + + const siblings = prop.getAllProperties().getProperties(); + + Phaser.Utils.Array.BringToTop(siblings, prop); + } + + break; + + case "Top": + + for (let i = 0; i < sel.length; i++) { + + const prop = sel[sel.length - i - 1]; + + const siblings = prop.getAllProperties().getProperties(); + + Phaser.Utils.Array.SendToBack(siblings, prop) + } + + break; + + case "Down": + + for (let i = 0; i < sel.length; i++) { + + const prop = sel[sel.length - i - 1]; + + const siblings = prop.getAllProperties().getProperties(); + + Phaser.Utils.Array.MoveUp(siblings, prop); + } + + break; + + case "Up": + + for (const prop of sel) { + + const siblings = prop.getAllProperties().getProperties(); + + Phaser.Utils.Array.MoveDown(siblings, prop); + } + + break; + } + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts index 205531bb2..8895e5787 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts @@ -34,32 +34,9 @@ namespace phasereditor2d.scene.ui.editor.properties { return colibri.ui.ide.Workbench.getWorkbench().getActiveEditor() as SceneEditor; } - static runPropertiesOperation(editor: SceneEditor, action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { - - const scene = editor.getScene(); - - const before = ui.editor.properties.ChangePrefabPropertiesOperation.snapshot(editor); - - action(scene.getPrefabUserProperties()); - - const after = ui.editor.properties.ChangePrefabPropertiesOperation.snapshot(editor); - - editor.getUndoManager() - .add(new ChangePrefabPropertiesOperation(editor, before, after)); - - editor.setDirty(true); - - editor.refreshOutline(); - - if (updateSelection) { - - editor.getSelectionManager().refreshSelection(); - } - } - protected runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { - PrefabPropertySection.runPropertiesOperation(this.getEditor(), action, updateSelection); + ui.editor.properties.ChangePrefabPropertiesOperation.runPropertiesOperation(this.getEditor(), action, updateSelection); } canEdit(obj: any, n: number): boolean { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts index 5d26b6fc8..1c2c48120 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts @@ -56,50 +56,8 @@ namespace phasereditor2d.scene.ui.editor.properties { const prop = this.getProperty(); - menu.addAction({ - text: "Move Up", - callback: () => { - this.runOperation(userProps => { - - const list = userProps.getProperties(); - - const i = list.indexOf(prop); - - if (i > 0) { - - const temp = list[i - 1]; - list[i - 1] = prop; - list[i] = temp; - } - }, true); - } - }); - - menu.addAction({ - text: "Move Down", - callback: () => { - this.runOperation(userProps => { - - const list = userProps.getProperties(); - - const i = list.indexOf(prop); - - if (i < list.length - 1) { - - const temp = list[i + 1]; - list[i + 1] = prop; - list[i] = temp; - } - }, true); - } - }); - - menu.addSeparator(); - menu.addMenu(this.createMorphMenu(prop)); - menu.addSeparator(); - menu.addAction({ text: "Delete", callback: () => { From 3a3c08f17318c7ea6fe7e76b376456be36e88cff Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 21:25:36 -0400 Subject: [PATCH 13/72] Updates changelog. --- CHANGELOG.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 6876cfaea..3445367dc 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -6,6 +6,8 @@ * A new Add Prefab Property command that shows a dialog. * Replaces the Object Depth commands for the Edit move commands. * Replaces the Object List sort commands by the Editor move commands. +* Allows change prefab properties with the Edit move commands. +* Removes the Move menu items from the Prefab Properties section. ## v3.61.0 - May 18, 2023 From 3aac0f9efb9bdcc1ecc0ae272f48c177d49a52e8 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 23:20:27 -0400 Subject: [PATCH 14/72] Allows copy/paste of prefab properties. --- .../editor/plugins/colibri/src/ui/ide/Part.ts | 1 + .../colibri/src/ui/ide/utils/NameMaker.ts | 6 +- .../src/ui/editor/ClipboardManager.ts | 57 +++++++++++++----- .../src/ui/editor/undo/PasteOperation.ts | 60 +++++++++++++++++-- .../userProperties/UserProperties.ts | 49 ++++++++++----- 5 files changed, 135 insertions(+), 38 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/ide/Part.ts b/source/editor/plugins/colibri/src/ui/ide/Part.ts index c755f98f5..8172b4c0f 100644 --- a/source/editor/plugins/colibri/src/ui/ide/Part.ts +++ b/source/editor/plugins/colibri/src/ui/ide/Part.ts @@ -90,6 +90,7 @@ namespace colibri.ui.ide { } getSelection() { + return this._selection; } diff --git a/source/editor/plugins/colibri/src/ui/ide/utils/NameMaker.ts b/source/editor/plugins/colibri/src/ui/ide/utils/NameMaker.ts index 2b4440813..747fd76af 100644 --- a/source/editor/plugins/colibri/src/ui/ide/utils/NameMaker.ts +++ b/source/editor/plugins/colibri/src/ui/ide/utils/NameMaker.ts @@ -22,16 +22,16 @@ namespace colibri.ui.ide.utils { } } - trimNumbering(name: string) { + static trimNumbering(name: string) { - return name.replace(/[0-9 _-]+$/, "") + return name.replace(/[0-9 _-]+$/, ""); } makeName(baseName: string) { if (this._nameSet.has(baseName)) { - baseName = this.trimNumbering(baseName); + baseName = NameMaker.trimNumbering(baseName); let name: string; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts index 41f885d53..e23e3c2a1 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts @@ -4,7 +4,7 @@ namespace phasereditor2d.scene.ui.editor { export interface IClipboardItem { - type: string; + type: "ISceneObject" | "ObjectList" | "PrefabProperty"; data: object; } @@ -31,12 +31,52 @@ namespace phasereditor2d.scene.ui.editor { ClipboardManager._clipboard = []; + this.copyGameObjects(); + + this.copyObjectLists(); + + this.copyPrefabProperties(); + } + + private copyPrefabProperties() { + + for (const prop of this._editor.getSelectedPrefabProperties()) { + + const data = {}; + + prop.writeJSON(data); + + ClipboardManager._clipboard.push({ + data, + type: "PrefabProperty" + }); + } + } + + private copyObjectLists() { + + for (const list of this._editor.getSelectedLists()) { + + const listData = {} as any; + list.writeJSON(listData); + + ClipboardManager._clipboard.push({ + type: "ObjectList", + data: listData + }); + } + } + + private copyGameObjects() { + let minX = Number.MAX_SAFE_INTEGER; let minY = Number.MAX_SAFE_INTEGER; const p = new Phaser.Math.Vector2(); - for (const obj of this._editor.getSelectedGameObjects()) { + const gameObjects = this._editor.getSelectedGameObjects(); + + for (const obj of gameObjects) { const sprite = obj as unknown as Phaser.GameObjects.Sprite; @@ -54,7 +94,7 @@ namespace phasereditor2d.scene.ui.editor { minY = Math.min(minY, p.y); } - for (const obj of this._editor.getSelectedGameObjects()) { + for (const obj of gameObjects) { const objData = {} as any; @@ -83,17 +123,6 @@ namespace phasereditor2d.scene.ui.editor { data: objData }); } - - for (const list of this._editor.getSelectedLists()) { - - const listData = {} as any; - list.writeJSON(listData); - - ClipboardManager._clipboard.push({ - type: "ObjectList", - data: listData - }); - } } paste(pasteInPlace: boolean) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts index 27b41627a..77fc72ec6 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts @@ -29,23 +29,73 @@ namespace phasereditor2d.scene.ui.editor.undo { const items = ClipboardManager.getClipboardCopy(); - const maker = this._editor.getSceneMaker(); - const sel = []; + this.pasteGameObjects(items, sel); + + this.pastePrefaProperties(items, sel); + + this._editor.setSelection(sel); + } + + private pastePrefaProperties(clipboardItems: IClipboardItem[], sel: any[]) { + const scene = this._editor.getScene(); + if (!scene.isPrefabSceneType()) { + + return; + } + + for (const item of clipboardItems) { + + if (item.type === "PrefabProperty") { + + const data = item.data as any; + + const id = data.type.id; + + const propType = ScenePlugin.getInstance().getUserPropertyType(id); + + if (propType) { + + const userProps = scene.getPrefabUserProperties(); + + const dataName = colibri.ui.ide.utils.NameMaker.trimNumbering(data.name); + const dataLabel = colibri.ui.ide.utils.NameMaker.trimNumbering(data.label); + + const { name, label } = userProps.createNewPropertyNameInfo(dataName, dataLabel); + + data.name = name; + data.label = label; + + const prop = userProps.createPropertyFromData(data); + + userProps.add(prop); + + sel.push(prop); + } + } + } + } + + private async pasteGameObjects(clipboardItems: IClipboardItem[], sel: any[]) { + + const scene = this._editor.getScene(); + + const maker = this._editor.getSceneMaker(); + const nameMaker = scene.createNameMaker(); const prefabObj = scene.getPrefabObject(); const sprites: sceneobjects.ISceneGameObject[] = []; - const displayList = items.filter(i => i.type === "ISceneObject").map(i => i.data as json.IObjectData); + const displayList = clipboardItems.filter(i => i.type === "ISceneObject").map(i => i.data as json.IObjectData); await scene.getMaker().updateLoaderWithData([], displayList); - for (const item of items) { + for (const item of clipboardItems) { if (item.type === "ISceneObject") { @@ -89,8 +139,6 @@ namespace phasereditor2d.scene.ui.editor.undo { } maker.afterDropObjects(prefabObj, sprites); - - this._editor.setSelection(sel); } private setNewObjectId(data: json.IObjectData) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts index b80a32339..7fb34d511 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts @@ -1,12 +1,12 @@ namespace phasereditor2d.scene.ui.sceneobjects { export abstract class UserProperties { - + private _properties: UserProperty[]; private _componentPropertyBuilder: TComponentPropertyBuilder; constructor(componentPropertyBuilder: TComponentPropertyBuilder) { - + this._componentPropertyBuilder = componentPropertyBuilder; this._properties = []; } @@ -17,7 +17,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { } deleteProperty(propName: string) { - + const prop = this._properties.find(p => p.getName() === propName); const i = this._properties.indexOf(prop); @@ -32,26 +32,47 @@ namespace phasereditor2d.scene.ui.sceneobjects { createProperty(propType: UserPropertyType) { + const { name, label } = this.createNewPropertyNameInfo("property", "Property"); + + const prop = new UserProperty(this, this._componentPropertyBuilder, { + defValue: propType.getDefaultValue(), + name, + label, + tooltip: "", + customDefinition: false, + type: propType + }); + + return prop; + } + + createNewPropertyNameInfo(baseName: string, baseLabel: string) { + let i = 0; while (true) { + i++; - const p = this._properties.find(p2 => p2.getInfo().name === "property" + i) + const p = this._properties.find(p2 => p2.getInfo().name === `${baseName}_${i}`); if (!p) { + break; } } - const prop = new UserProperty(this, this._componentPropertyBuilder, { - defValue: propType.getDefaultValue(), - label: "Property " + i, - name: "property" + i, - tooltip: "Property " + i, - customDefinition: false, - type: propType - }); + return { + name: `${baseName}_${i}`, + label: `${baseLabel} ${i}` + } + } + + createPropertyFromData(data: any) { + + const prop = new UserProperty(this, this._componentPropertyBuilder); + + prop.readJSON(data); return prop; } @@ -62,9 +83,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { for (const propData of data) { - const prop = new UserProperty(this, this._componentPropertyBuilder); - - prop.readJSON(propData); + const prop = this.createPropertyFromData(propData); this._properties.push(prop); } From 73973a3b2a8e54318103282c63f62cd2943dbd98 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 1 Jun 2023 23:22:09 -0400 Subject: [PATCH 15/72] Updates changelog. --- CHANGELOG.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 3445367dc..3b8555e3f 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -6,8 +6,8 @@ * A new Add Prefab Property command that shows a dialog. * Replaces the Object Depth commands for the Edit move commands. * Replaces the Object List sort commands by the Editor move commands. -* Allows change prefab properties with the Edit move commands. -* Removes the Move menu items from the Prefab Properties section. +* Allows change prefab properties with the Edit move commands. Remove the Move options from the Prefab Properties section's menu. +* Allows copy/paste of prefab properties. ## v3.61.0 - May 18, 2023 From a8035042caa155d8d8b68d900068c7af5768645a Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 2 Jun 2023 00:42:29 -0400 Subject: [PATCH 16/72] Allows order commands for plain objects. --- .../ui/editor/commands/SceneEditorCommands.ts | 39 +++++- ...eration.ts => GameObjectDepthOperation.ts} | 4 +- .../editor/undo/PlainObjectOrderOperation.ts | 131 ++++++++++++++++++ 3 files changed, 166 insertions(+), 8 deletions(-) rename source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/{DepthOperation.ts => GameObjectDepthOperation.ts} (96%) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index e2f3d6ecc..f99b3e53d 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -143,13 +143,15 @@ namespace phasereditor2d.scene.ui.editor.commands { this.registerOriginCommands(manager); - this.registerDepthCommands(manager); + this.registerGameObjectDepthCommands(manager); + + this.registerPlainObjectOrderCommands(manager); this.registerListCommands(manager); this.registerTypeCommands(manager); - this.registerMoveObjectCommands(manager); + this.registerTranslateObjectCommands(manager); this.registerTextureCommands(manager); @@ -164,6 +166,31 @@ namespace phasereditor2d.scene.ui.editor.commands { this.registerPropertiesCommands(manager); } + static registerPlainObjectOrderCommands(manager: colibri.ui.ide.commands.CommandManager) { + + const moves: [undo.DepthMove, string][] = [ + ["Up", CMD_SORT_OBJ_UP], + ["Down", CMD_SORT_OBJ_DOWN], + ["Top", CMD_SORT_OBJ_TOP], + ["Bottom", CMD_SORT_OBJ_BOTTOM] + ]; + + for (const tuple of moves) { + + const move = tuple[0]; + const cmd = tuple[1]; + + manager.addHandlerHelper(cmd, + // testFunc + args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 + && undo.PlainObjectOrderOperation.allow(args.activeEditor as any, move), + // execFunc + args => args.activeEditor.getUndoManager().add( + new undo.PlainObjectOrderOperation(args.activeEditor as editor.SceneEditor, move) + )); + } + } + private static registerPrefabCommands(manager: colibri.ui.ide.commands.CommandManager) { manager.add({ @@ -1137,7 +1164,7 @@ namespace phasereditor2d.scene.ui.editor.commands { }); } - private static registerMoveObjectCommands(manager: colibri.ui.ide.commands.CommandManager) { + private static registerTranslateObjectCommands(manager: colibri.ui.ide.commands.CommandManager) { class Operation extends undo.SceneSnapshotOperation { @@ -2082,7 +2109,7 @@ namespace phasereditor2d.scene.ui.editor.commands { }); } - private static registerDepthCommands(manager: colibri.ui.ide.commands.CommandManager) { + private static registerGameObjectDepthCommands(manager: colibri.ui.ide.commands.CommandManager) { const moves: [undo.DepthMove, string][] = [ ["Up", CMD_SORT_OBJ_UP], @@ -2099,10 +2126,10 @@ namespace phasereditor2d.scene.ui.editor.commands { manager.addHandlerHelper(cmd, // testFunc args => isSceneScope(args) && args.activeEditor.getSelection().length > 0 - && undo.DepthOperation.allow(args.activeEditor as any, move), + && undo.GameObjectDepthOperation.allow(args.activeEditor as any, move), // execFunc args => args.activeEditor.getUndoManager().add( - new undo.DepthOperation(args.activeEditor as editor.SceneEditor, move) + new undo.GameObjectDepthOperation(args.activeEditor as editor.SceneEditor, move) )); } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DepthOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/GameObjectDepthOperation.ts similarity index 96% rename from source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DepthOperation.ts rename to source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/GameObjectDepthOperation.ts index 78d59750f..cc91742b3 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DepthOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/GameObjectDepthOperation.ts @@ -2,7 +2,7 @@ namespace phasereditor2d.scene.ui.editor.undo { export declare type DepthMove = "Up" | "Down" | "Top" | "Bottom"; - export class DepthOperation extends SceneSnapshotOperation { + export class GameObjectDepthOperation extends SceneSnapshotOperation { private _depthMove: DepthMove; @@ -80,7 +80,7 @@ namespace phasereditor2d.scene.ui.editor.undo { protected async performModification() { - const sel = DepthOperation.sortedSelection(this.getEditor()); + const sel = GameObjectDepthOperation.sortedSelection(this.getEditor()); switch (this._depthMove) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts new file mode 100644 index 000000000..228ece856 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts @@ -0,0 +1,131 @@ +namespace phasereditor2d.scene.ui.editor.undo { + + export class PlainObjectOrderOperation extends SceneSnapshotOperation { + + private _depthMove: DepthMove; + + constructor(editor: SceneEditor, depthMove: DepthMove) { + super(editor); + + this._depthMove = depthMove; + } + + private static getSibling(editor: SceneEditor, obj: sceneobjects.IScenePlainObject) { + + const objES = obj.getEditorSupport(); + + const category = objES.getExtension().getCategory(); + + const siblings = editor.getScene().getPlainObjectsByCategory(category); + + return siblings; + } + + static allow(editor: SceneEditor, move: DepthMove) { + + // sort the selection and filter off non-game-objects + let sel = editor.getSelectedPlainObjects(); + + // if the sorted selection contains all the selected objects + if (sel.length !== editor.getSelection().length) { + + return false; + } + + for (const obj of sel) { + + const siblings = this.getSibling(editor, obj); + + const index = siblings.indexOf(obj); + + let bottomIndex = 0; + const len = siblings.length; + + if (move === "Bottom" || move === "Down") { + + if (index === len - 1) { + + return false; + } + + } else { // Top || Up + + if (index === bottomIndex) { + + return false; + } + } + } + + return true; + } + + protected async performModification() { + + const editor = this.getEditor(); + + const sel = editor.getSelectedPlainObjects(); + + const plainObjects = editor.getScene().getPlainObjects(); + + switch (this._depthMove) { + + case "Bottom": + + for (const obj of sel) { + + const siblings = PlainObjectOrderOperation.getSibling(editor, obj); + + const start = plainObjects.indexOf(siblings[0]); + + Phaser.Utils.Array.BringToTop(siblings, obj); + + plainObjects.splice(start, siblings.length, ...siblings); + } + + break; + + case "Top": + + console.log("here"); + + for (let i = 0; i < sel.length; i++) { + + const obj = sel[sel.length - i - 1]; + + const siblings = PlainObjectOrderOperation.getSibling(editor, obj); + + const start = plainObjects.indexOf(siblings[0]); + + Phaser.Utils.Array.SendToBack(siblings, obj); + + plainObjects.splice(start, siblings.length, ...siblings); + } + + break; + + case "Down": + + for (let i = 0; i < sel.length; i++) { + + const obj = sel[sel.length - i - 1]; + + Phaser.Utils.Array.MoveUp(plainObjects, obj); + } + + break; + + case "Up": + + for (const obj of sel) { + + Phaser.Utils.Array.MoveDown(plainObjects, obj); + } + + break; + } + + this.getEditor().repaint(); + } + } +} \ No newline at end of file From 503f0ca1709b550516a36fded89cd0d27aea7497 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 2 Jun 2023 00:46:51 -0400 Subject: [PATCH 17/72] Fixes selection order in keyboard key order commands. --- .../editor/undo/PlainObjectOrderOperation.ts | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts index 228ece856..d63542c92 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PlainObjectOrderOperation.ts @@ -24,7 +24,7 @@ namespace phasereditor2d.scene.ui.editor.undo { static allow(editor: SceneEditor, move: DepthMove) { // sort the selection and filter off non-game-objects - let sel = editor.getSelectedPlainObjects(); + let sel = this.sortedSelection(editor); // if the sorted selection contains all the selected objects if (sel.length !== editor.getSelection().length) { @@ -64,7 +64,7 @@ namespace phasereditor2d.scene.ui.editor.undo { const editor = this.getEditor(); - const sel = editor.getSelectedPlainObjects(); + const sel = PlainObjectOrderOperation.sortedSelection(editor); const plainObjects = editor.getScene().getPlainObjects(); @@ -87,8 +87,6 @@ namespace phasereditor2d.scene.ui.editor.undo { case "Top": - console.log("here"); - for (let i = 0; i < sel.length; i++) { const obj = sel[sel.length - i - 1]; @@ -127,5 +125,22 @@ namespace phasereditor2d.scene.ui.editor.undo { this.getEditor().repaint(); } + + private static sortedSelection(editor: SceneEditor) { + + const sel = editor.getSelectedPlainObjects(); + + const plainObjects = editor.getScene().getPlainObjects(); + + sel.sort((a, b) => { + + const aa = plainObjects.indexOf(a); + const bb = plainObjects.indexOf(b); + + return aa - bb; + }); + + return sel; + } } } \ No newline at end of file From 00d0eaedba503acc61f0e09d5c84231addce3763 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 2 Jun 2023 00:56:15 -0400 Subject: [PATCH 18/72] Fixes paste operation regression. --- .../phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts index 77fc72ec6..8c36411f9 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts @@ -31,7 +31,7 @@ namespace phasereditor2d.scene.ui.editor.undo { const sel = []; - this.pasteGameObjects(items, sel); + await this.pasteGameObjects(items, sel); this.pastePrefaProperties(items, sel); From 4cbe52e9fd79dac20530f96c58b425f725379f06 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 2 Jun 2023 00:59:36 -0400 Subject: [PATCH 19/72] Fixes selection ordering in prefab properties order command. --- .../properties/PrefabPropertyOrderAction.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts index f0e8f091a..408f5b7ae 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts @@ -4,7 +4,7 @@ namespace phasereditor2d.scene.ui.editor.properties { static allow(editor: SceneEditor, move: ui.editor.undo.DepthMove) { - const sel: ui.sceneobjects.UserProperty[] = editor.getSelection(); + const sel = this.sortedSelection(editor); if (sel.length === 0) { @@ -48,7 +48,7 @@ namespace phasereditor2d.scene.ui.editor.properties { static execute(editor: SceneEditor, depthMove: undo.DepthMove): void { - const sel = editor.getSelection() as any as sceneobjects.UserProperty[]; + const sel = this.sortedSelection(editor); switch (depthMove) { @@ -101,5 +101,21 @@ namespace phasereditor2d.scene.ui.editor.properties { break; } } + + private static sortedSelection(editor: SceneEditor) { + + const sel = editor.getSelection() as any as sceneobjects.UserProperty[]; + const props = editor.getScene().getPrefabUserProperties().getProperties(); + + sel.sort((a, b) => { + + const aa = props.indexOf(a); + const bb = props.indexOf(b); + + return aa - bb; + }); + + return sel; + } } } \ No newline at end of file From 66fb217433290d6e5aa0e4644886aeb4570ff749 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 10:19:26 -0400 Subject: [PATCH 20/72] Allows copy/paste keyboard key objects. --- .vscode/settings.json | 2 +- .../phasereditor2d.scene/src/ui/Scene.ts | 35 +++++++++++------ .../src/ui/editor/ClipboardManager.ts | 19 +++++++++- .../src/ui/editor/undo/PasteOperation.ts | 38 +++++++++++++++++++ .../src/ui/sceneobjects/EditorSupport.ts | 3 +- .../src/ui/sceneobjects/Utils.ts | 5 +++ 6 files changed, 88 insertions(+), 14 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e4084b21b..ff45a1acc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "workbench.colorTheme": "GitHub Dark" + "workbench.colorTheme": "Solarized Dark" } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/Scene.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/Scene.ts index 2e91883c5..3e04363ce 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/Scene.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/Scene.ts @@ -84,20 +84,29 @@ namespace phasereditor2d.scene.ui { for (const objData of list) { - const ext = ScenePlugin.getInstance().getPlainObjectExtensionByObjectType(objData.type); + this.readPlainObject(objData); + } + } - if (ext) { + readPlainObject(objData: core.json.IScenePlainObjectData) { - const plainObject = ext.createPlainObjectWithData({ - scene: this, - data: objData - }); + const ext = ScenePlugin.getInstance().getPlainObjectExtensionByObjectType(objData.type); - plainObject.getEditorSupport().readJSON(objData); + if (ext) { - this.addPlainObject(plainObject); - } + const plainObject = ext.createPlainObjectWithData({ + scene: this, + data: objData + }); + + plainObject.getEditorSupport().readJSON(objData); + + this.addPlainObject(plainObject); + + return plainObject; } + + return undefined; } removePlainObjects(objects: sceneobjects.IScenePlainObject[]) { @@ -371,9 +380,11 @@ namespace phasereditor2d.scene.ui { const nameMaker = new colibri.ui.ide.utils.NameMaker((obj: any) => { - if (sceneobjects.isGameObject(obj)) { + const objES = sceneobjects.EditorSupport.getEditorSupport(obj); - return (obj as sceneobjects.ISceneGameObject).getEditorSupport().getLabel(); + if (objES) { + + return objES.getLabel(); } return (obj as sceneobjects.ObjectList).getLabel(); @@ -389,6 +400,8 @@ namespace phasereditor2d.scene.ui { || objES.isPrefeabInstanceAppendedChild;; }); + nameMaker.update(this._plainObjects); + for (const list of this._objectLists.getLists()) { nameMaker.update([list]); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts index e23e3c2a1..2670fc6b6 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/ClipboardManager.ts @@ -4,7 +4,7 @@ namespace phasereditor2d.scene.ui.editor { export interface IClipboardItem { - type: "ISceneObject" | "ObjectList" | "PrefabProperty"; + type: "ISceneObject" | "IScenePlainObject" | "ObjectList" | "PrefabProperty"; data: object; } @@ -33,11 +33,28 @@ namespace phasereditor2d.scene.ui.editor { this.copyGameObjects(); + this.copyPlainObjects(); + this.copyObjectLists(); this.copyPrefabProperties(); } + private copyPlainObjects() { + + for(const obj of this._editor.getSelectedPlainObjects()) { + + const data: any = {}; + + obj.getEditorSupport().writeJSON(data); + + ClipboardManager._clipboard.push({ + data, + type: "IScenePlainObject" + }); + } + } + private copyPrefabProperties() { for (const prop of this._editor.getSelectedPrefabProperties()) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts index 8c36411f9..984a8d940 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/PasteOperation.ts @@ -33,11 +33,49 @@ namespace phasereditor2d.scene.ui.editor.undo { await this.pasteGameObjects(items, sel); + await this.pastePlainObjects(items, sel); + this.pastePrefaProperties(items, sel); this._editor.setSelection(sel); } + private async pastePlainObjects(clipboardItems: IClipboardItem[], sel: any[]) { + + const scene = this._editor.getScene(); + + const nameMaker = scene.createNameMaker(); + + const plainObjects: sceneobjects.IScenePlainObject[] = []; + + const dataList = clipboardItems.filter(i => i.type === "IScenePlainObject").map(i => i.data as json.IScenePlainObjectData); + + await scene.getMaker().updateLoaderWithData([], dataList); + + for (const data of dataList) { + + this.setNewObjectId(data); + + const obj =scene.readPlainObject(data); + + if (obj) { + + plainObjects.push(obj); + + sel.push(obj); + } + } + + for (const newObj of plainObjects) { + + const oldLabel = newObj.getEditorSupport().getLabel(); + + const newLabel = nameMaker.makeName(oldLabel); + + newObj.getEditorSupport().setLabel(newLabel); + } + } + private pastePrefaProperties(clipboardItems: IClipboardItem[], sel: any[]) { const scene = this._editor.getScene(); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/EditorSupport.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/EditorSupport.ts index 6d9e18016..84a9f3cc0 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/EditorSupport.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/EditorSupport.ts @@ -27,9 +27,10 @@ namespace phasereditor2d.scene.ui.sceneobjects { const support = obj["getEditorSupport"](); - if (support instanceof EditorSupport) + if (support instanceof EditorSupport) { return support; + } } return null; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Utils.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Utils.ts index 11a3e12c6..f01fb282c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Utils.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Utils.ts @@ -72,4 +72,9 @@ namespace phasereditor2d.scene.ui.sceneobjects { return GameObjectEditorSupport.hasEditorSupport(obj); } + + export function isPlainObject(obj: any) { + + return ScenePlainObjectEditorSupport.hasEditorSupport(obj); + } } \ No newline at end of file From 2f5ac7c5b08ad7c3307cc73ae52b83f37e8f51f9 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 10:40:00 -0400 Subject: [PATCH 21/72] Allows cut plain objects. --- .../src/ui/editor/undo/CutOperation.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts index ab3e73653..fb650dcb9 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts @@ -12,6 +12,8 @@ namespace phasereditor2d.scene.ui.editor.undo { this._editor.getClipboardManager().copy(); + const scene = this.getScene(); + const lists = this._editor.getScene().getObjectLists(); for (const obj of this._editor.getSelection()) { @@ -24,12 +26,24 @@ namespace phasereditor2d.scene.ui.editor.undo { lists .removeObjectById(sprite.getEditorSupport().getId()); - } else if (obj instanceof sceneobjects.ObjectList) { + } + } + + for (const obj of this._editor.getSelection()) { + + if (obj instanceof sceneobjects.ObjectList) { lists.removeListById(obj.getId()); } } + const plainObjects = this._editor.getSelectedPlainObjects(); + + if (plainObjects.length > 0) { + + scene.removePlainObjects(plainObjects); + } + this._editor.setSelection([]); } } From 16b7e14a6d56dea35b9c8db7e0288935f333945e Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 10:40:31 -0400 Subject: [PATCH 22/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 3b8555e3f..65571aa6c 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -8,6 +8,7 @@ * Replaces the Object List sort commands by the Editor move commands. * Allows change prefab properties with the Edit move commands. Remove the Move options from the Prefab Properties section's menu. * Allows copy/paste of prefab properties. +* Allows cut/copy/paste keyboard keys. ## v3.61.0 - May 18, 2023 From 39ee072d8d506491d20360c746f60f000c364b65 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 10:56:52 -0400 Subject: [PATCH 23/72] Allows cut prefab properties. --- .../src/ui/editor/undo/CutOperation.ts | 37 +++++++++++-------- .../userProperties/UserProperties.ts | 7 ++++ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts index fb650dcb9..37a349b2a 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts @@ -12,38 +12,45 @@ namespace phasereditor2d.scene.ui.editor.undo { this._editor.getClipboardManager().copy(); - const scene = this.getScene(); + const scene = this.getScene(); const lists = this._editor.getScene().getObjectLists(); - for (const obj of this._editor.getSelection()) { + // delete game objects - if (sceneobjects.isGameObject(obj)) { + for (const obj of this._editor.getSelectedGameObjects()) { - const sprite = obj as sceneobjects.ISceneGameObject; + const objES = obj.getEditorSupport(); - sprite.getEditorSupport().destroy(); - lists - .removeObjectById(sprite.getEditorSupport().getId()); + objES.destroy(); + lists.removeObjectById(objES.getId()); + } + + // delete plain objects + + const plainObjects = this._editor.getSelectedPlainObjects(); + + if (plainObjects.length > 0) { - } + scene.removePlainObjects(plainObjects); } - for (const obj of this._editor.getSelection()) { + // delete ObjectLists - if (obj instanceof sceneobjects.ObjectList) { + for (const objectList of this._editor.getSelectedLists()) { - lists.removeListById(obj.getId()); - } + lists.removeListById(objectList.getId()); } - const plainObjects = this._editor.getSelectedPlainObjects(); + // delete prefab properties - if (plainObjects.length > 0) { + for (const prop of this._editor.getSelectedPrefabProperties()) { - scene.removePlainObjects(plainObjects); + prop.getAllProperties().deleteProperty(prop.getName()); } + // clear selection + this._editor.setSelection([]); } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts index 7fb34d511..07f0d8519 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts @@ -48,6 +48,13 @@ namespace phasereditor2d.scene.ui.sceneobjects { createNewPropertyNameInfo(baseName: string, baseLabel: string) { + const p = this._properties.find(p2 => p2.getInfo().name === baseName); + + if (!p) { + + return { name: baseName, label: baseLabel }; + } + let i = 0; while (true) { From 4981a337521e44f121e00166df7b51e6902f382a Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 10:57:20 -0400 Subject: [PATCH 24/72] Updates changelog. --- CHANGELOG.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 65571aa6c..6268d3ce6 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -7,8 +7,8 @@ * Replaces the Object Depth commands for the Edit move commands. * Replaces the Object List sort commands by the Editor move commands. * Allows change prefab properties with the Edit move commands. Remove the Move options from the Prefab Properties section's menu. -* Allows copy/paste of prefab properties. -* Allows cut/copy/paste keyboard keys. +* Allows copy/cut/paste of prefab properties. +* Allows copy/cut/paste keyboard keys. ## v3.61.0 - May 18, 2023 From 387707d8a4d4441d432c942e61a0e78e55c3a49c Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 11:21:33 -0400 Subject: [PATCH 25/72] Renames UserProperties to UserPropertiesManager. --- .../properties/ChangePrefabPropertiesOperation.ts | 2 +- .../ui/editor/properties/PrefabPropertiesSection.ts | 2 +- .../ui/editor/properties/PrefabPropertyOrderAction.ts | 10 +++++----- .../src/ui/editor/properties/PrefabPropertySection.ts | 6 +++--- .../ui/editor/properties/SingleUserPropertySection.ts | 4 ++-- .../src/ui/editor/properties/UserPropertiesSection.ts | 4 ++-- .../src/ui/editor/undo/CutOperation.ts | 2 +- .../src/ui/editor/undo/DeleteOperation.ts | 2 +- .../src/ui/editor/usercomponent/UserComponent.ts | 2 +- .../ui/editor/usercomponent/UserComponentProperties.ts | 4 ++-- .../usercomponent/UserComponentPropertySection.ts | 6 +++--- .../ui/editor/usercomponent/UserComponentsEditor.ts | 4 ++-- .../userProperties/PrefabUserProperties.ts | 4 ++-- .../{UserProperties.ts => UserPropertiesManager.ts} | 2 +- .../src/ui/sceneobjects/userProperties/UserProperty.ts | 10 +++++----- 15 files changed, 32 insertions(+), 32 deletions(-) rename source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/{UserProperties.ts => UserPropertiesManager.ts} (98%) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts index e28e9f1c0..38bb0049c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/ChangePrefabPropertiesOperation.ts @@ -22,7 +22,7 @@ namespace phasereditor2d.scene.ui.editor.properties { return data; } - static runPropertiesOperation(editor: SceneEditor, action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { + static runPropertiesOperation(editor: SceneEditor, action: (props?: sceneobjects.UserPropertiesManager) => void, updateSelection?: boolean) { const scene = editor.getScene(); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts index aa0527f5e..b83258ff1 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertiesSection.ts @@ -26,7 +26,7 @@ namespace phasereditor2d.scene.ui.editor.properties { SingleUserPropertySection.createAddProprtyButton(comp, this, action => this.runOperation(action), selector); } - runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection = true) { + runOperation(action: (props?: sceneobjects.UserPropertiesManager) => void, updateSelection = true) { ui.editor.properties.ChangePrefabPropertiesOperation.runPropertiesOperation(this.getEditor(), action, updateSelection); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts index 408f5b7ae..c3198940b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertyOrderAction.ts @@ -19,7 +19,7 @@ namespace phasereditor2d.scene.ui.editor.properties { } } - const siblings = sel[0].getAllProperties().getProperties(); + const siblings = sel[0].getManager().getProperties(); for (const prop of sel) { @@ -56,7 +56,7 @@ namespace phasereditor2d.scene.ui.editor.properties { for (const prop of sel) { - const siblings = prop.getAllProperties().getProperties(); + const siblings = prop.getManager().getProperties(); Phaser.Utils.Array.BringToTop(siblings, prop); } @@ -69,7 +69,7 @@ namespace phasereditor2d.scene.ui.editor.properties { const prop = sel[sel.length - i - 1]; - const siblings = prop.getAllProperties().getProperties(); + const siblings = prop.getManager().getProperties(); Phaser.Utils.Array.SendToBack(siblings, prop) } @@ -82,7 +82,7 @@ namespace phasereditor2d.scene.ui.editor.properties { const prop = sel[sel.length - i - 1]; - const siblings = prop.getAllProperties().getProperties(); + const siblings = prop.getManager().getProperties(); Phaser.Utils.Array.MoveUp(siblings, prop); } @@ -93,7 +93,7 @@ namespace phasereditor2d.scene.ui.editor.properties { for (const prop of sel) { - const siblings = prop.getAllProperties().getProperties(); + const siblings = prop.getManager().getProperties(); Phaser.Utils.Array.MoveDown(siblings, prop); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts index 8895e5787..0e3e2eed7 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/PrefabPropertySection.ts @@ -14,9 +14,9 @@ namespace phasereditor2d.scene.ui.editor.properties { return "scene-editor/prefab-user-properties.html"; } - protected getUserProperties(): sceneobjects.UserProperties { + protected getUserProperties(): sceneobjects.UserPropertiesManager { - return this.getProperty().getAllProperties(); + return this.getProperty().getManager(); } protected getProperty(): sceneobjects.UserProperty { @@ -34,7 +34,7 @@ namespace phasereditor2d.scene.ui.editor.properties { return colibri.ui.ide.Workbench.getWorkbench().getActiveEditor() as SceneEditor; } - protected runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { + protected runOperation(action: (props?: sceneobjects.UserPropertiesManager) => void, updateSelection?: boolean) { ui.editor.properties.ChangePrefabPropertiesOperation.runPropertiesOperation(this.getEditor(), action, updateSelection); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts index 1c2c48120..fd9c6ba7a 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SingleUserPropertySection.ts @@ -7,13 +7,13 @@ namespace phasereditor2d.scene.ui.editor.properties { protected abstract getSectionHelpPath(): string; - protected abstract getUserProperties(): sceneobjects.UserProperties; + protected abstract getUserProperties(): sceneobjects.UserPropertiesManager; protected abstract getProperty(): sceneobjects.UserProperty; protected abstract componentTitleUpdated(): void; - protected abstract runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean); + protected abstract runOperation(action: (props?: sceneobjects.UserPropertiesManager) => void, updateSelection?: boolean); static createAddProprtyButton( comp: HTMLDivElement, diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts index faa352e89..6550b7414 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/UserPropertiesSection.ts @@ -2,7 +2,7 @@ namespace phasereditor2d.scene.ui.editor.properties { import controls = colibri.ui.controls; - export declare type TUserPropertiesAction = (props?: sceneobjects.UserProperties) => void + export declare type TUserPropertiesAction = (props?: sceneobjects.UserPropertiesManager) => void export abstract class UserPropertiesSection extends controls.properties.PropertySection { @@ -10,7 +10,7 @@ namespace phasereditor2d.scene.ui.editor.properties { protected abstract getSectionHelpPath(): string; - protected abstract getUserProperties(): sceneobjects.UserProperties; + protected abstract getUserProperties(): sceneobjects.UserPropertiesManager; protected abstract runOperation(action: TUserPropertiesAction, updateSelection?: boolean); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts index 37a349b2a..bda5af882 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CutOperation.ts @@ -46,7 +46,7 @@ namespace phasereditor2d.scene.ui.editor.undo { for (const prop of this._editor.getSelectedPrefabProperties()) { - prop.getAllProperties().deleteProperty(prop.getName()); + prop.getManager().deleteProperty(prop.getName()); } // clear selection diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DeleteOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DeleteOperation.ts index eaf453c2e..8103fc6c0 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DeleteOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/DeleteOperation.ts @@ -40,7 +40,7 @@ namespace phasereditor2d.scene.ui.editor.undo { for(const obj of editor.getSelectedPrefabProperties()) { - obj.getAllProperties().deleteProperty(obj.getName()); + obj.getManager().deleteProperty(obj.getName()); } scene.removePlainObjects(editor.getSelectedPlainObjects()); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponent.ts index a975e7439..c09180d4c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponent.ts @@ -7,7 +7,7 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { private _name: string; private _baseClass: string; private _gameObjectType: string; - private _properties: sceneobjects.UserProperties; + private _properties: sceneobjects.UserPropertiesManager; constructor(name: string) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentProperties.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentProperties.ts index e09605e10..f3cf55b36 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentProperties.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentProperties.ts @@ -1,9 +1,9 @@ -/// +/// /// /// namespace phasereditor2d.scene.ui.editor.usercomponent { - export class UserComponentProperties extends sceneobjects.UserProperties { + export class UserComponentProperties extends sceneobjects.UserPropertiesManager { private _userComponent: UserComponent; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentPropertySection.ts index 244fa9961..b0d9a1147 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentPropertySection.ts @@ -23,9 +23,9 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { .getSelectedEditor() as UserComponentsEditor; } - protected getUserProperties(): sceneobjects.UserProperties { + protected getUserProperties(): sceneobjects.UserPropertiesManager { - return this.getSelectionFirstElement().getAllProperties(); + return this.getSelectionFirstElement().getManager(); } protected getProperty(): sceneobjects.UserProperty { @@ -38,7 +38,7 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { this.getEditor().refreshViewers(); } - runOperation(action: (props?: sceneobjects.UserProperties) => void, updateSelection?: boolean) { + runOperation(action: (props?: sceneobjects.UserPropertiesManager) => void, updateSelection?: boolean) { this.getEditor().runOperation(() => action(this.getUserProperties())); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentsEditor.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentsEditor.ts index b7085ba31..58580a0c3 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentsEditor.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/usercomponent/UserComponentsEditor.ts @@ -208,7 +208,7 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { if (obj instanceof sceneobjects.UserProperty) { - const comp = (obj.getAllProperties() as UserComponentProperties).getUserComponent(); + const comp = (obj.getManager() as UserComponentProperties).getUserComponent(); return { component: comp.getName(), @@ -452,7 +452,7 @@ namespace phasereditor2d.scene.ui.editor.usercomponent { } else if (obj instanceof sceneobjects.UserProperty) { - obj.getAllProperties().deleteProperty(obj.getName()); + obj.getManager().deleteProperty(obj.getName()); } else if (typeof obj === "string") { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/PrefabUserProperties.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/PrefabUserProperties.ts index 27c5015c9..b5661b4a6 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/PrefabUserProperties.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/PrefabUserProperties.ts @@ -1,4 +1,4 @@ -/// +/// namespace phasereditor2d.scene.ui.sceneobjects { export function PrefabUserPropertyBuilder(prop: UserProperty) { @@ -12,7 +12,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { return new PrefabUserPropertyWrapper(prop); } - export class PrefabUserProperties extends UserProperties { + export class PrefabUserProperties extends UserPropertiesManager { constructor() { super(PrefabUserPropertyBuilder); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserPropertiesManager.ts similarity index 98% rename from source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts rename to source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserPropertiesManager.ts index 07f0d8519..fb0993100 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperties.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserPropertiesManager.ts @@ -1,6 +1,6 @@ namespace phasereditor2d.scene.ui.sceneobjects { - export abstract class UserProperties { + export abstract class UserPropertiesManager { private _properties: UserProperty[]; private _componentPropertyBuilder: TComponentPropertyBuilder; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts index 6f57726cf..e21b91718 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/UserProperty.ts @@ -16,18 +16,18 @@ namespace phasereditor2d.scene.ui.sceneobjects { private _info: IUserPropertyInfo; private _componentProperty: IProperty; private _componentPropertyBuilder: TComponentPropertyBuilder; - private _allProperties: UserProperties; + private _manager: UserPropertiesManager; - constructor(allProperties: UserProperties, componentPropertyBuilder: TComponentPropertyBuilder, info?: IUserPropertyInfo) { + constructor(allProperties: UserPropertiesManager, componentPropertyBuilder: TComponentPropertyBuilder, info?: IUserPropertyInfo) { - this._allProperties = allProperties; + this._manager = allProperties; this._componentPropertyBuilder = componentPropertyBuilder; this._info = info; } - getAllProperties() { + getManager() { - return this._allProperties; + return this._manager; } getComponentProperty(): IProperty { From ddfe4094b3f5eb2ed49ae56a73ddcc00c5c84adb Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 15:08:11 -0400 Subject: [PATCH 26/72] Allows selecting keyboard key and object list objects in the Object Variable property dialog. --- .../phasereditor2d.scene/src/ScenePlugin.ts | 9 +----- .../userProperties/ObjectVarPropertyType.ts | 28 ++++++++++++++++--- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index a40b3af9d..a884ad239 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -469,17 +469,10 @@ namespace phasereditor2d.scene { return settings; } - private _userPropertyTypes: ui.sceneobjects.UserPropertyType[]; - getUserPropertyTypes() { - if (this._userPropertyTypes) { - - return this._userPropertyTypes; - } - // TODO: we should do this via extension - return this._userPropertyTypes = [ + return [ new ui.sceneobjects.NumberPropertyType(), new ui.sceneobjects.StringPropertyType(), new ui.sceneobjects.BooleanPropertyType(), diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts index 5c0c3023c..e69a2ed81 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts @@ -64,15 +64,23 @@ namespace phasereditor2d.scene.ui.sceneobjects { return core.code.SceneCodeDOMBuilder.getPrefabInstanceVarName(value); } - return objES.getLabel(); + return core.code.formatToValidVarName(objES.getLabel()); } - return viewer.getLabelProvider().getLabel(value); + return core.code.formatToValidVarName(viewer.getLabelProvider().getLabel(value)); } protected loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer): void { - viewer.setInput(this.getEditor().getScene().getGameObjects()); + const scene = this.getEditor().getScene(); + + const input = [ + ...scene.getGameObjects(), + ...scene.getPlainObjects(), + ...scene.getObjectLists().getLists() + ]; + + viewer.setInput(input); } protected async updateIcon(iconControl: controls.IconControl, value: string): Promise { @@ -109,7 +117,19 @@ namespace phasereditor2d.scene.ui.sceneobjects { } }); - const found = foundElement[0]; + let found = foundElement[0]; + + if (!found) { + + found = scene.getPlainObjects().find( + obj => core.code.formatToValidVarName(obj.getEditorSupport().getLabel()) === value); + } + + if (!found) { + + found = scene.getObjectLists().getLists() + .find(l => core.code.formatToValidVarName(l.getLabel()) === value); + } if (found) { From 8a3c60d41b64a75671bc8fad06925f798ffe2781 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 15:09:17 -0400 Subject: [PATCH 27/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 6268d3ce6..5839aa6cf 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -9,6 +9,7 @@ * Allows change prefab properties with the Edit move commands. Remove the Move options from the Prefab Properties section's menu. * Allows copy/cut/paste of prefab properties. * Allows copy/cut/paste keyboard keys. +* Shows Keyboard.Key and Object List objects in the Object Variable user property's dialog.. ## v3.61.0 - May 18, 2023 From e9da3f5ef4b4182d5712d42c7e1bc07ff795e50d Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 16:36:20 -0400 Subject: [PATCH 28/72] Adds the new KeyCode User Property. --- .../src/ui/controls/properties/FormBuilder.ts | 5 +- .../phasereditor2d.scene/src/ScenePlugin.ts | 1 + .../keyboard/KeyboardKeySection.ts | 35 +------- .../keyboard/KeyboardKeyViewer.ts | 16 ++++ .../properties/SceneGameObjectSection.ts | 15 ++++ .../object/properties/SceneObjectSection.ts | 37 ++++++++ .../userProperties/ColorPropertyType.ts | 11 --- .../userProperties/KeyCodePropertyType.ts | 84 +++++++++++++++++++ 8 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeyViewer.ts create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/KeyCodePropertyType.ts diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/FormBuilder.ts b/source/editor/plugins/colibri/src/ui/controls/properties/FormBuilder.ts index beac02617..39e915126 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/FormBuilder.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/FormBuilder.ts @@ -47,7 +47,10 @@ namespace colibri.ui.controls.properties { btn.addEventListener("click", e => callback(e)); - parent.appendChild(btn); + if (parent) { + + parent.appendChild(btn); + } return btn; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index a884ad239..a70770ad2 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -477,6 +477,7 @@ namespace phasereditor2d.scene { new ui.sceneobjects.StringPropertyType(), new ui.sceneobjects.BooleanPropertyType(), new ui.sceneobjects.ColorPropertyType(), + new ui.sceneobjects.KeyCodePropertyType(), new ui.sceneobjects.ExpressionPropertyType(), new ui.sceneobjects.OptionPropertyType(), new ui.sceneobjects.ObjectVarPropertyType(), diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeySection.ts index eaa67cb32..1f3eeb276 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeySection.ts @@ -17,40 +17,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { this.createLabel(comp, "Key Code", "The keycode of this key"); - const btn = this.createButton(comp, "KeyCode", e => { - - const viewer = new controls.viewers.TreeViewer(KeyboardKeySection.ID + ".keyCodes"); - viewer.setLabelProvider(new controls.viewers.LabelProvider(obj => obj)); - viewer.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); - viewer.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider()); - viewer.setInput(KeyboardKeyExtension.getInstance().getKeyCodes()); - viewer.revealAndSelect(this.getSelectionFirstElement().keyCode); - - const dlg = new controls.dialogs.ViewerDialog(viewer, false); - - dlg.create(); - - dlg.setTitle("Select Key Code"); - - dlg.addOpenButton("Select", (sel) => { - - const value = sel[0]; - const keys = this.getSelection(); - - console.log("set", value, "to", keys[0].getEditorSupport().getId()); - - this.getEditor().getUndoManager().add( - new SimpleOperation(this.getEditor(), keys, KeyboardKeyComponent.keyCode, value)); - - }, false); - - dlg.addCancelButton(); - }); - - this.addUpdater(() => { - - btn.textContent = this.flatValues_StringOneOrNothing(this.getSelection().map(k => k.keyCode)); - }); + this.createKeyCodeField(comp, KeyboardKeyComponent.keyCode); } canEdit(obj: any, n: number): boolean { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeyViewer.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeyViewer.ts new file mode 100644 index 000000000..06ab32e2f --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/keyboard/KeyboardKeyViewer.ts @@ -0,0 +1,16 @@ +namespace phasereditor2d.scene.ui.sceneobjects { + + import controls = colibri.ui.controls; + + export class KeyboardKeysViewer extends controls.viewers.TreeViewer { + + constructor() { + super("KeyboardKeysViewer"); + + this.setLabelProvider(new controls.viewers.LabelProvider(obj => obj)); + this.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); + this.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider()); + this.setInput(KeyboardKeyExtension.getInstance().getKeyCodes()); + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneGameObjectSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneGameObjectSection.ts index 6ed9555ea..7eb807ca2 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneGameObjectSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneGameObjectSection.ts @@ -204,6 +204,21 @@ namespace phasereditor2d.scene.ui.sceneobjects { return text; } + createKeyCodeRow(parent: HTMLElement, prop: IProperty, lockIcon: boolean = true) { + + if (lockIcon) { + + this.createLock(parent, prop); + } + + const labelElement = this.createLabel(parent, prop.label, PhaserHelp(prop.tooltip)); + labelElement.style.gridColumn = "2"; + + const buttonElement = this.createKeyCodeField(parent, prop); + + return { labelElement, buttonElement }; + } + createPropertyEnumRow(parent: HTMLElement, prop: IEnumProperty, lockIcon: boolean = true, filter?: (v: any) => boolean) { if (lockIcon) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneObjectSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneObjectSection.ts index 90c95fc02..5dfa2c403 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneObjectSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/SceneObjectSection.ts @@ -197,6 +197,43 @@ namespace phasereditor2d.scene.ui.sceneobjects { return colorElement; } + createKeyCodeField(parent: HTMLElement, property: IProperty) { + + const btn = this.createButton(parent, "KeyCode", e => { + + const viewer = new KeyboardKeysViewer(); + + const selObj = this.getSelectionFirstElement(); + const keyCode = property.getValue(selObj); + + viewer.revealAndSelect(keyCode); + + const dlg = new controls.dialogs.ViewerDialog(viewer, false); + + dlg.create(); + + dlg.setTitle("Select Key Code"); + + dlg.addOpenButton("Select", (sel) => { + + const value = sel[0]; + const keys = this.getSelection(); + + this.getEditor().getUndoManager().add( + new SimpleOperation(this.getEditor(), keys, KeyboardKeyComponent.keyCode, value)); + + }, false); + + dlg.addCancelButton(); + }); + + this.addUpdater(() => { + + btn.textContent = this.flatValues_StringOneOrNothing( + this.getSelection().map(obj => property.getValue(obj))); + }); + } + createBooleanField(parent: HTMLElement, property: IProperty, checkUnlock = true) { const labelElement = this.createLabel(parent, property.label, PhaserHelp(property.tooltip)); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ColorPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ColorPropertyType.ts index 1c3a431a0..13d3e6182 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ColorPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ColorPropertyType.ts @@ -37,17 +37,6 @@ namespace phasereditor2d.scene.ui.sceneobjects { }; } - private createEditorComp() { - - const comp = document.createElement("div"); - comp.style.display = "grid"; - comp.style.gridTemplateColumns = "1fr auto"; - comp.style.gap = "5px"; - comp.style.alignItems = "center"; - - return comp; - } - createInspectorPropertyEditor(section: SceneGameObjectSection, parent: HTMLElement, userProp: UserProperty, lockIcon: boolean): void { section.createPropertyColorRow(parent, userProp.getComponentProperty(), true, lockIcon); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/KeyCodePropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/KeyCodePropertyType.ts new file mode 100644 index 000000000..34c9faa02 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/KeyCodePropertyType.ts @@ -0,0 +1,84 @@ +/// +namespace phasereditor2d.scene.ui.sceneobjects { + + import controls = colibri.ui.controls; + import code = core.code; + + export class KeyCodePropertyType extends UserPropertyType { + + constructor(typeId = "keycode") { + super(typeId, "SPACE"); + } + + getName(): string { + + return "Key Code"; + } + + createEditorElement(getValue: () => any, setValue: (value: any) => void): IPropertyEditor { + + const formBuilder = new controls.properties.FormBuilder(); + + const btn = formBuilder.createButton(undefined, "Key Code", e => { + + const viewer = new KeyboardKeysViewer(); + + const keyCode = getValue(); + viewer.revealAndSelect(keyCode); + + const dlg = new controls.dialogs.ViewerDialog(viewer, false); + + dlg.create(); + + dlg.setTitle("Select Key Code"); + + dlg.addOpenButton("Select", (sel) => { + + const value = sel[0]; + + setValue(value); + + }, false); + + dlg.addCancelButton(); + }); + + const update = () => { + + btn.textContent = getValue(); + }; + + return { + element: btn, + update + }; + } + + createInspectorPropertyEditor(section: SceneGameObjectSection, parent: HTMLElement, userProp: UserProperty, lockIcon: boolean): void { + + section.createKeyCodeRow(parent, userProp.getComponentProperty(), lockIcon); + } + + renderValue(value: string): string { + + return value; + } + + buildDeclarePropertyCodeDOM(prop: UserProperty, value: string): core.code.FieldDeclCodeDOM { + + return this.buildExpressionFieldCode(prop, "number", `Phaser.Input.Keyboard.KeyCodes.${value}`); + } + + buildSetObjectPropertyCodeDOM(comp: Component, args: ISetObjectPropertiesCodeDOMArgs, userProp: UserProperty): void { + + comp.buildSetObjectPropertyCodeDOM([userProp.getComponentProperty()], args2 => { + + const dom = new code.AssignPropertyCodeDOM(args2.fieldCodeName, args.objectVarName); + + dom.value(`Phaser.Input.Keyboard.KeyCodes.${args2.value}`); + + args.statements.push(dom); + }); + } + } +} \ No newline at end of file From 4fe7629ad4e1b4c6ef555e1119487b2bdf2e04c9 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 6 Jun 2023 16:36:44 -0400 Subject: [PATCH 29/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 5839aa6cf..d3ae786b4 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -10,6 +10,7 @@ * Allows copy/cut/paste of prefab properties. * Allows copy/cut/paste keyboard keys. * Shows Keyboard.Key and Object List objects in the Object Variable user property's dialog.. +* Adds the new KeyCode User Property. ## v3.61.0 - May 18, 2023 From 655b0675aba97a7d295edbf007967222442afdc9 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 9 Jun 2023 21:35:25 -0400 Subject: [PATCH 30/72] Fixes hit area serealization. --- .vscode/settings.json | 2 +- .../src/ui/sceneobjects/Component.ts | 6 +++++- .../ui/sceneobjects/hitArea/BaseHitAreaComponent.ts | 11 +++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ff45a1acc..02578b575 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "workbench.colorTheme": "Solarized Dark" + "workbench.colorTheme": "Nord" } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts index 0a7db2c38..79fcefa75 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts @@ -74,7 +74,11 @@ namespace phasereditor2d.scene.ui.sceneobjects { for (const prop of properties) { - ser.write(prop.name, prop.getValue(this._obj), this.getPropertyDefaultValue(prop)); + const value = prop.getValue(this._obj); + + const defValue = this.getPropertyDefaultValue(prop); + + ser.write(prop.name, value, defValue); } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts index d105205c4..94a391dd3 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/hitArea/BaseHitAreaComponent.ts @@ -35,6 +35,17 @@ namespace phasereditor2d.scene.ui.sceneobjects { super.readJSON(ser); } + writeJSON(ser: core.json.Serializer): void { + + // only writes this component data if its shape is selected + const shape = HitAreaComponent.hitAreaShape.getValue(this.getObject()); + + if (shape === this._shape) { + + super.writeJSON(ser); + } + } + protected abstract _setDefaultValues(x: number, y: number, width: number, height: number): void; setDefaultValues() { From d53bf7b674e81bfc882689da0b56b691247292b3 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 9 Jun 2023 21:36:08 -0400 Subject: [PATCH 31/72] Updates changeloog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index d3ae786b4..daee53d86 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -11,6 +11,7 @@ * Allows copy/cut/paste keyboard keys. * Shows Keyboard.Key and Object List objects in the Object Variable user property's dialog.. * Adds the new KeyCode User Property. +* Fixes hit area serialization. ## v3.61.0 - May 18, 2023 From 73828be4b2a303006205299cbd47a7bbc6286ff7 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 14 Jun 2023 02:28:23 -0400 Subject: [PATCH 32/72] Adds new user Event Property type. --- scripts/make-events-files.js | 39 +++ .../ui/controls/viewers/EmptyCellRenderer.ts | 1 + .../viewers/EmptyCellRendererProvider.ts | 1 + .../src/ui/controls/viewers/LabelProvider.ts | 1 + .../phasereditor2d.ide/src/core/PhaserDocs.ts | 38 ++- .../data/events-docs.json | 250 ++++++++++++++++++ .../plugins/phasereditor2d.scene/plugin.json | 3 +- .../phasereditor2d.scene/src/ScenePlugin.ts | 20 +- .../src/core/code/SceneCodeDOMBuilder.ts | 3 +- .../src/ui/sceneobjects/Component.ts | 3 +- .../AbstractDialogPropertyType.ts | 8 +- .../userProperties/EventPropertyType.ts | 151 +++++++++++ .../styles/EventPropertyDialog.css | 10 + 13 files changed, 511 insertions(+), 17 deletions(-) create mode 100644 scripts/make-events-files.js create mode 100644 source/editor/plugins/phasereditor2d.scene/data/events-docs.json create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts create mode 100644 source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css diff --git a/scripts/make-events-files.js b/scripts/make-events-files.js new file mode 100644 index 000000000..6d474a256 --- /dev/null +++ b/scripts/make-events-files.js @@ -0,0 +1,39 @@ + +const fs = require("fs"); +const process = require("process") + +const phaser_path = process.env.PHASER_PATH; +const phaser_json_path = phaser_path + "/phaser3-docs/json/phaser.json"; + +const content = fs.readFileSync(phaser_json_path); + +const data = JSON.parse(content.toString()); + +const docsMap = {}; + +let i = 1; + +for (const item of data.docs) { + + if (item.kind !== "event") { + + continue; + } + + let { name, memberof } = item; + + const fullName = `${memberof}.${name}`; + + docsMap[fullName] = item.description || item.classdesc; + + console.log(`${i++} Processing event fullName`); +} + +const output = JSON.stringify(docsMap, null, 2); + +console.log("---"); +console.log("Writing to file events.json..."); + +fs.writeFileSync("../source/editor/plugins/phasereditor2d.scene/data/events-docs.json", output); + +console.log("Done."); \ No newline at end of file diff --git a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRenderer.ts b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRenderer.ts index 8f86eb2e7..b87d664d9 100644 --- a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRenderer.ts +++ b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRenderer.ts @@ -6,6 +6,7 @@ namespace colibri.ui.controls.viewers { private _variableSize: boolean; constructor(variableSize: boolean = true) { + this._variableSize = variableSize; } diff --git a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts index 8bc169a11..96a125324 100644 --- a/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts +++ b/source/editor/plugins/colibri/src/ui/controls/viewers/EmptyCellRendererProvider.ts @@ -10,6 +10,7 @@ namespace colibri.ui.controls.viewers { } constructor(getRenderer?: (element: any) => ICellRenderer) { + this._getRenderer = getRenderer ?? ((e) => new EmptyCellRenderer()); } diff --git a/source/editor/plugins/colibri/src/ui/controls/viewers/LabelProvider.ts b/source/editor/plugins/colibri/src/ui/controls/viewers/LabelProvider.ts index 5608a7575..d63279e21 100644 --- a/source/editor/plugins/colibri/src/ui/controls/viewers/LabelProvider.ts +++ b/source/editor/plugins/colibri/src/ui/controls/viewers/LabelProvider.ts @@ -16,6 +16,7 @@ namespace colibri.ui.controls.viewers { } if (typeof (obj) === "string") { + return obj; } diff --git a/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts b/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts index b729e6448..5ce28fe2d 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts @@ -4,43 +4,57 @@ namespace phasereditor2d.ide.core { private _data: any = null; private _plugin: colibri.Plugin; - private _filePath: string; + private _files: string[]; - constructor(plugin: colibri.Plugin, filePath: string) { + constructor(plugin: colibri.Plugin, ...files: string[]) { this._plugin = plugin; - this._filePath = filePath; + this._files = files; } async preload() { if (!this._data) { - console.log("Loading jsdoc " + this._plugin.getId() + ": " + this._filePath); + this._data = {}; - this._data = await this._plugin.getJSON(this._filePath); + for (const file of this._files) { - const converter = new showdown.Converter(); + console.log("Loading jsdoc " + this._plugin.getId() + ": " + file); - // tslint:disable-next-line:forin - for (const k in this._data) { + const fileData = await this._plugin.getJSON(file); - const help = this._data[k]; + const converter = new showdown.Converter(); - this._data[k] = converter.makeHtml(help); + // tslint:disable-next-line:forin + for (const k in fileData) { + + const help = fileData[k]; + + this._data[k] = converter.makeHtml(help); + } } } } - getDoc(helpKey: string): string { + getDoc(helpKey: string, wrap = true): string { if (helpKey in this._data) { - return `${helpKey}

${this._data[helpKey]}
`; + if (wrap) { + + return `${helpKey}

${this._data[helpKey]}
`; + } + + return this._data[helpKey]; } return "Help not found for: " + helpKey; } + getKeys() { + + return Object.keys(this._data); + } } } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/data/events-docs.json b/source/editor/plugins/phasereditor2d.scene/data/events-docs.json new file mode 100644 index 000000000..0698bad4a --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/data/events-docs.json @@ -0,0 +1,250 @@ +{ + "Phaser.Animations.Events.ADD_ANIMATION": "The Add Animation Event.\n\nThis event is dispatched when a new animation is added to the global Animation Manager.\n\nThis can happen either as a result of an animation instance being added to the Animation Manager,\nor the Animation Manager creating a new animation directly.", + "Phaser.Animations.Events.ANIMATION_COMPLETE": "The Animation Complete Event.\n\nThis event is dispatched by a Sprite when an animation playing on it completes playback.\nThis happens when the animation gets to the end of its sequence, factoring in any delays\nor repeats it may have to process.\n\nAn animation that is set to loop, or repeat forever, will never fire this event, because\nit never actually completes. If you need to handle this, listen for the `ANIMATION_STOP`\nevent instead, as this is emitted when the animation is stopped directly.\n\nListen for it on the Sprite using `sprite.on('animationcomplete', listener)`\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_COMPLETE_KEY": "The Animation Complete Dynamic Key Event.\n\nThis event is dispatched by a Sprite when an animation playing on it completes playback.\nThis happens when the animation gets to the end of its sequence, factoring in any delays\nor repeats it may have to process.\n\nAn animation that is set to loop, or repeat forever, will never fire this event, because\nit never actually completes. If you need to handle this, listen for the `ANIMATION_STOP`\nevent instead, as this is emitted when the animation is stopped directly.\n\nThe difference between this and the `ANIMATION_COMPLETE` event is that this one has a\ndynamic event name that contains the name of the animation within it. For example,\nif you had an animation called `explode` you could listen for the completion of that\nspecific animation by using: `sprite.on('animationcomplete-explode', listener)`. Or, if you\nwish to use types: `sprite.on(Phaser.Animations.Events.ANIMATION_COMPLETE_KEY + 'explode', listener)`.\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_REPEAT": "The Animation Repeat Event.\n\nThis event is dispatched by a Sprite when an animation repeats playing on it.\nThis happens if the animation was created, or played, with a `repeat` value specified.\n\nAn animation will repeat when it reaches the end of its sequence.\n\nListen for it on the Sprite using `sprite.on('animationrepeat', listener)`\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_RESTART": "The Animation Restart Event.\n\nThis event is dispatched by a Sprite when an animation restarts playing on it.\nThis only happens when the `Sprite.anims.restart` method is called.\n\nListen for it on the Sprite using `sprite.on('animationrestart', listener)`\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_START": "The Animation Start Event.\n\nThis event is dispatched by a Sprite when an animation starts playing on it.\nThis happens when the animation is played, factoring in any delay that may have been specified.\nThis event happens after the delay has expired and prior to the first update event.\n\nListen for it on the Sprite using `sprite.on('animationstart', listener)`\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_STOP": "The Animation Stop Event.\n\nThis event is dispatched by a Sprite when an animation is stopped on it. An animation\nwill only be stopeed if a method such as `Sprite.stop` or `Sprite.anims.stopAfterDelay`\nis called. It can also be emitted if a new animation is started before the current one completes.\n\nListen for it on the Sprite using `sprite.on('animationstop', listener)`\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.ANIMATION_UPDATE": "The Animation Update Event.\n\nThis event is dispatched by a Sprite when an animation playing on it updates. This happens when the animation changes frame.\nAn animation will change frame based on the frame rate and other factors like `timeScale` and `delay`. It can also change\nframe when stopped or restarted.\n\nListen for it on the Sprite using `sprite.on('animationupdate', listener)`\n\nIf an animation is playing faster than the game frame-rate can handle, it's entirely possible for it to emit several\nupdate events in a single game frame, so please be aware of this in your code. The **final** event received that frame\nis the one that is rendered to the game.\n\nThe animation event flow is as follows:\n\n1. `ANIMATION_START`\n2. `ANIMATION_UPDATE` (repeated for however many frames the animation has)\n3. `ANIMATION_REPEAT` (only if the animation is set to repeat, it then emits more update events after this)\n4. `ANIMATION_COMPLETE` (only if there is a finite, or zero, repeat count)\n5. `ANIMATION_COMPLETE_KEY` (only if there is a finite, or zero, repeat count)\n\nIf the animation is stopped directly, the `ANIMATION_STOP` event is dispatched instead of `ANIMATION_COMPLETE`.\n\nIf the animation is restarted while it is already playing, `ANIMATION_RESTART` is emitted.", + "Phaser.Animations.Events.PAUSE_ALL": "The Pause All Animations Event.\n\nThis event is dispatched when the global Animation Manager is told to pause.\n\nWhen this happens all current animations will stop updating, although it doesn't necessarily mean\nthat the game has paused as well.", + "Phaser.Animations.Events.REMOVE_ANIMATION": "The Remove Animation Event.\n\nThis event is dispatched when an animation is removed from the global Animation Manager.", + "Phaser.Animations.Events.RESUME_ALL": "The Resume All Animations Event.\n\nThis event is dispatched when the global Animation Manager resumes, having been previously paused.\n\nWhen this happens all current animations will continue updating again.", + "Phaser.Cache.Events.ADD": "The Cache Add Event.\n\nThis event is dispatched by any Cache that extends the BaseCache each time a new object is added to it.", + "Phaser.Cache.Events.REMOVE": "The Cache Remove Event.\n\nThis event is dispatched by any Cache that extends the BaseCache each time an object is removed from it.", + "Phaser.Cameras.Scene2D.Events.DESTROY": "The Destroy Camera Event.\n\nThis event is dispatched by a Camera instance when it is destroyed by the Camera Manager.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('cameradestroy', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.DESTROY, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE": "The Camera Fade In Complete Event.\n\nThis event is dispatched by a Camera instance when the Fade In Effect completes.\n\nListen to it from a Camera instance using `Camera.on('camerafadeincomplete', listener)`.", + "Phaser.Cameras.Scene2D.Events.FADE_IN_START": "The Camera Fade In Start Event.\n\nThis event is dispatched by a Camera instance when the Fade In Effect starts.\n\nListen to it from a Camera instance using `Camera.on('camerafadeinstart', listener)`.", + "Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE": "The Camera Fade Out Complete Event.\n\nThis event is dispatched by a Camera instance when the Fade Out Effect completes.\n\nListen to it from a Camera instance using `Camera.on('camerafadeoutcomplete', listener)`.", + "Phaser.Cameras.Scene2D.Events.FADE_OUT_START": "The Camera Fade Out Start Event.\n\nThis event is dispatched by a Camera instance when the Fade Out Effect starts.\n\nListen to it from a Camera instance using `Camera.on('camerafadeoutstart', listener)`.", + "Phaser.Cameras.Scene2D.Events.FLASH_COMPLETE": "The Camera Flash Complete Event.\n\nThis event is dispatched by a Camera instance when the Flash Effect completes.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('cameraflashcomplete', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.FLASH_COMPLETE, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.FLASH_START": "The Camera Flash Start Event.\n\nThis event is dispatched by a Camera instance when the Flash Effect starts.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('cameraflashstart', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.FLASH_START, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.FOLLOW_UPDATE": "The Camera Follower Update Event.\n\nThis event is dispatched by a Camera instance when it is following a\nGame Object and the Camera position has been updated as a result of\nthat following.\n\nListen to it from a Camera instance using: `camera.on('followupdate', listener)`.", + "Phaser.Cameras.Scene2D.Events.PAN_COMPLETE": "The Camera Pan Complete Event.\n\nThis event is dispatched by a Camera instance when the Pan Effect completes.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerapancomplete', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.PAN_COMPLETE, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.PAN_START": "The Camera Pan Start Event.\n\nThis event is dispatched by a Camera instance when the Pan Effect starts.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerapanstart', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.PAN_START, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.POST_RENDER": "The Camera Post-Render Event.\n\nThis event is dispatched by a Camera instance after is has finished rendering.\nIt is only dispatched if the Camera is rendering to a texture.\n\nListen to it from a Camera instance using: `camera.on('postrender', listener)`.", + "Phaser.Cameras.Scene2D.Events.PRE_RENDER": "The Camera Pre-Render Event.\n\nThis event is dispatched by a Camera instance when it is about to render.\nIt is only dispatched if the Camera is rendering to a texture.\n\nListen to it from a Camera instance using: `camera.on('prerender', listener)`.", + "Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETE": "The Camera Rotate Complete Event.\n\nThis event is dispatched by a Camera instance when the Rotate Effect completes.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerarotatecomplete', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETE, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.ROTATE_START": "The Camera Rotate Start Event.\n\nThis event is dispatched by a Camera instance when the Rotate Effect starts.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerarotatestart', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.ROTATE_START, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.SHAKE_COMPLETE": "The Camera Shake Complete Event.\n\nThis event is dispatched by a Camera instance when the Shake Effect completes.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerashakecomplete', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.SHAKE_COMPLETE, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.SHAKE_START": "The Camera Shake Start Event.\n\nThis event is dispatched by a Camera instance when the Shake Effect starts.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerashakestart', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.SHAKE_START, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.ZOOM_COMPLETE": "The Camera Zoom Complete Event.\n\nThis event is dispatched by a Camera instance when the Zoom Effect completes.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerazoomcomplete', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.ZOOM_COMPLETE, () => {});\n```", + "Phaser.Cameras.Scene2D.Events.ZOOM_START": "The Camera Zoom Start Event.\n\nThis event is dispatched by a Camera instance when the Zoom Effect starts.\n\nListen for it via either of the following:\n\n```js\nthis.cameras.main.on('camerazoomstart', () => {});\n```\n\nor use the constant, to avoid having to remember the correct event string:\n\n```js\nthis.cameras.main.on(Phaser.Cameras.Scene2D.Events.ZOOM_START, () => {});\n```", + "Phaser.Core.Events.BLUR": "The Game Blur Event.\n\nThis event is dispatched by the Game Visibility Handler when the window in which the Game instance is embedded\nenters a blurred state. The blur event is raised when the window loses focus. This can happen if a user swaps\ntab, or if they simply remove focus from the browser to another app.", + "Phaser.Core.Events.BOOT": "The Game Boot Event.\n\nThis event is dispatched when the Phaser Game instance has finished booting, but before it is ready to start running.\nThe global systems use this event to know when to set themselves up, dispatching their own `ready` events as required.", + "Phaser.Core.Events.CONTEXT_LOST": "The Game Context Lost Event.\n\nThis event is dispatched by the Game if the WebGL Renderer it is using encounters a WebGL Context Lost event from the browser.\n\nThe renderer halts all rendering and cannot resume after this happens.", + "Phaser.Core.Events.DESTROY": "The Game Destroy Event.\n\nThis event is dispatched when the game instance has been told to destroy itself.\nLots of internal systems listen to this event in order to clear themselves out.\nCustom plugins and game code should also do the same.", + "Phaser.Core.Events.FOCUS": "The Game Focus Event.\n\nThis event is dispatched by the Game Visibility Handler when the window in which the Game instance is embedded\nenters a focused state. The focus event is raised when the window re-gains focus, having previously lost it.", + "Phaser.Core.Events.HIDDEN": "The Game Hidden Event.\n\nThis event is dispatched by the Game Visibility Handler when the document in which the Game instance is embedded\nenters a hidden state. Only browsers that support the Visibility API will cause this event to be emitted.\n\nIn most modern browsers, when the document enters a hidden state, the Request Animation Frame and setTimeout, which\ncontrol the main game loop, will automatically pause. There is no way to stop this from happening. It is something\nyour game should account for in its own code, should the pause be an issue (i.e. for multiplayer games)", + "Phaser.Core.Events.PAUSE": "The Game Pause Event.\n\nThis event is dispatched when the Game loop enters a paused state, usually as a result of the Visibility Handler.", + "Phaser.Core.Events.POST_RENDER": "The Game Post-Render Event.\n\nThis event is dispatched right at the end of the render process.\n\nEvery Scene will have rendered and been drawn to the canvas by the time this event is fired.\nUse it for any last minute post-processing before the next game step begins.", + "Phaser.Core.Events.POST_STEP": "The Game Post-Step Event.\n\nThis event is dispatched after the Scene Manager has updated.\nHook into it from plugins or systems that need to do things before the render starts.", + "Phaser.Core.Events.PRE_RENDER": "The Game Pre-Render Event.\n\nThis event is dispatched immediately before any of the Scenes have started to render.\n\nThe renderer will already have been initialized this frame, clearing itself and preparing to receive the Scenes for rendering, but it won't have actually drawn anything yet.", + "Phaser.Core.Events.PRE_STEP": "The Game Pre-Step Event.\n\nThis event is dispatched before the main Game Step starts. By this point in the game cycle none of the Scene updates have yet happened.\nHook into it from plugins or systems that need to update before the Scene Manager does.", + "Phaser.Core.Events.READY": "The Game Ready Event.\n\nThis event is dispatched when the Phaser Game instance has finished booting, the Texture Manager is fully ready,\nand all local systems are now able to start.", + "Phaser.Core.Events.RESUME": "The Game Resume Event.\n\nThis event is dispatched when the game loop leaves a paused state and resumes running.", + "Phaser.Core.Events.STEP": "The Game Step Event.\n\nThis event is dispatched after the Game Pre-Step and before the Scene Manager steps.\nHook into it from plugins or systems that need to update before the Scene Manager does, but after the core Systems have.", + "Phaser.Core.Events.VISIBLE": "The Game Visible Event.\n\nThis event is dispatched by the Game Visibility Handler when the document in which the Game instance is embedded\nenters a visible state, previously having been hidden.\n\nOnly browsers that support the Visibility API will cause this event to be emitted.", + "Phaser.Data.Events.CHANGE_DATA": "The Change Data Event.\n\nThis event is dispatched by a Data Manager when an item in the data store is changed.\n\nGame Objects with data enabled have an instance of a Data Manager under the `data` property. So, to listen for\na change data event from a Game Object you would use: `sprite.on('changedata', listener)`.\n\nThis event is dispatched for all items that change in the Data Manager.\nTo listen for the change of a specific item, use the `CHANGE_DATA_KEY_EVENT` event.", + "Phaser.Data.Events.CHANGE_DATA_KEY": "The Change Data Key Event.\n\nThis event is dispatched by a Data Manager when an item in the data store is changed.\n\nGame Objects with data enabled have an instance of a Data Manager under the `data` property. So, to listen for\nthe change of a specific data item from a Game Object you would use: `sprite.on('changedata-key', listener)`,\nwhere `key` is the unique string key of the data item. For example, if you have a data item stored called `gold`\nthen you can listen for `sprite.on('changedata-gold')`.", + "Phaser.Data.Events.DESTROY": "The Data Manager Destroy Event.\n\nThe Data Manager will listen for the destroy event from its parent, and then close itself down.", + "Phaser.Data.Events.REMOVE_DATA": "The Remove Data Event.\n\nThis event is dispatched by a Data Manager when an item is removed from it.\n\nGame Objects with data enabled have an instance of a Data Manager under the `data` property. So, to listen for\nthe removal of a data item on a Game Object you would use: `sprite.on('removedata', listener)`.", + "Phaser.Data.Events.SET_DATA": "The Set Data Event.\n\nThis event is dispatched by a Data Manager when a new item is added to the data store.\n\nGame Objects with data enabled have an instance of a Data Manager under the `data` property. So, to listen for\nthe addition of a new data item on a Game Object you would use: `sprite.on('setdata', listener)`.", + "Phaser.GameObjects.Events.ADDED_TO_SCENE": "The Game Object Added to Scene Event.\n\nThis event is dispatched when a Game Object is added to a Scene.\n\nListen for it on a Game Object instance using `GameObject.on('addedtoscene', listener)`.", + "Phaser.GameObjects.Events.DESTROY": "The Game Object Destroy Event.\n\nThis event is dispatched when a Game Object instance is being destroyed.\n\nListen for it on a Game Object instance using `GameObject.on('destroy', listener)`.", + "Phaser.GameObjects.Events.REMOVED_FROM_SCENE": "The Game Object Removed from Scene Event.\n\nThis event is dispatched when a Game Object is removed from a Scene.\n\nListen for it on a Game Object instance using `GameObject.on('removedfromscene', listener)`.", + "Phaser.GameObjects.Events.VIDEO_COMPLETE": "The Video Game Object Complete Event.\n\nThis event is dispatched when a Video finishes playback by reaching the end of its duration. It\nis also dispatched if a video marker sequence is being played and reaches the end.\n\nNote that not all videos can fire this event. Live streams, for example, have no fixed duration,\nso never technically 'complete'.\n\nIf a video is stopped from playback, via the `Video.stop` method, it will emit the\n`VIDEO_STOP` event instead of this one.\n\nListen for it from a Video Game Object instance using `Video.on('complete', listener)`.", + "Phaser.GameObjects.Events.VIDEO_CREATED": "The Video Game Object Created Event.\n\nThis event is dispatched when the texture for a Video has been created. This happens\nwhen enough of the video source has been loaded that the browser is able to render a\nframe from it.\n\nListen for it from a Video Game Object instance using `Video.on('created', listener)`.", + "Phaser.GameObjects.Events.VIDEO_ERROR": "The Video Game Object Error Event.\n\nThis event is dispatched when a Video tries to play a source that does not exist, or is the wrong file type.\n\nListen for it from a Video Game Object instance using `Video.on('error', listener)`.", + "Phaser.GameObjects.Events.VIDEO_LOCKED": "The Video Game Object Locked Event.\n\nThis event is dispatched when a Video was attempted to be played, but the browser prevented it\nfrom doing so due to the Media Engagement Interaction policy.\n\nIf you get this event you will need to wait for the user to interact with the browser before\nthe video will play. This is a browser security measure to prevent autoplaying videos with\naudio. An interaction includes a mouse click, a touch, or a key press.\n\nListen for it from a Video Game Object instance using `Video.on('locked', listener)`.", + "Phaser.GameObjects.Events.VIDEO_LOOP": "The Video Game Object Loop Event.\n\nThis event is dispatched when a Video that is currently playing has looped. This only\nhappens if the `loop` parameter was specified, or the `setLoop` method was called,\nand if the video has a fixed duration. Video streams, for example, cannot loop, as\nthey have no duration.\n\nLooping is based on the result of the Video `timeupdate` event. This event is not\nframe-accurate, due to the way browsers work, so please do not rely on this loop\nevent to be time or frame precise.\n\nListen for it from a Video Game Object instance using `Video.on('loop', listener)`.", + "Phaser.GameObjects.Events.VIDEO_PLAYING": "The Video Game Object Playing Event.\n\nThe playing event is fired after playback is first started,\nand whenever it is restarted. For example it is fired when playback\nresumes after having been paused or delayed due to lack of data.\n\nListen for it from a Video Game Object instance using `Video.on('playing', listener)`.", + "Phaser.GameObjects.Events.VIDEO_PLAY": "The Video Game Object Play Event.\n\nThis event is dispatched when a Video begins playback. For videos that do not require\ninteraction unlocking, this is usually as soon as the `Video.play` method is called.\nHowever, for videos that require unlocking, it is fired once playback begins after\nthey've been unlocked.\n\nListen for it from a Video Game Object instance using `Video.on('play', listener)`.", + "Phaser.GameObjects.Events.VIDEO_SEEKED": "The Video Game Object Seeked Event.\n\nThis event is dispatched when a Video completes seeking to a new point in its timeline.\n\nListen for it from a Video Game Object instance using `Video.on('seeked', listener)`.", + "Phaser.GameObjects.Events.VIDEO_SEEKING": "The Video Game Object Seeking Event.\n\nThis event is dispatched when a Video _begins_ seeking to a new point in its timeline.\nWhen the seek is complete, it will dispatch the `VIDEO_SEEKED` event to conclude.\n\nListen for it from a Video Game Object instance using `Video.on('seeking', listener)`.", + "Phaser.GameObjects.Events.VIDEO_STALLED": "The Video Game Object Stalled Event.\n\nThis event is dispatched by a Video Game Object when the video playback stalls.\n\nThis can happen if the video is buffering.\n\nIf will fire for any of the following native DOM events:\n\n`stalled`\n`suspend`\n`waiting`\n\nListen for it from a Video Game Object instance using `Video.on('stalled', listener)`.\n\nNote that being stalled isn't always a negative thing. A video can be stalled if it\nhas downloaded enough data in to its buffer to not need to download any more until\nthe current batch of frames have rendered.", + "Phaser.GameObjects.Events.VIDEO_STOP": "The Video Game Object Stopped Event.\n\nThis event is dispatched when a Video is stopped from playback via a call to the `Video.stop` method,\neither directly via game code, or indirectly as the result of changing a video source or destroying it.\n\nListen for it from a Video Game Object instance using `Video.on('stop', listener)`.", + "Phaser.GameObjects.Events.VIDEO_TEXTURE": "The Video Game Object Texture Ready Event.\n\nThis event is dispatched by a Video Game Object when it has finished creating its texture.\n\nThis happens when the video has finished loading enough data for its first frame.\n\nIf you wish to use the Video texture elsewhere in your game, such as as a Sprite texture,\nthen you should listen for this event first, before creating the Sprites that use it.\n\nListen for it from a Video Game Object instance using `Video.on('textureready', listener)`.", + "Phaser.GameObjects.Events.VIDEO_UNLOCKED": "The Video Game Object Unlocked Event.\n\nThis event is dispatched when a Video that was prevented from playback due to the browsers\nMedia Engagement Interaction policy, is unlocked by a user gesture.\n\nListen for it from a Video Game Object instance using `Video.on('unlocked', listener)`.", + "Phaser.GameObjects.Events.VIDEO_UNSUPPORTED": "The Video Game Object Unsupported Event.\n\nThis event is dispatched by a Video Game Object if the media source\n(which may be specified as a MediaStream, MediaSource, Blob, or File,\nfor example) doesn't represent a supported media format.\n\nListen for it from a Video Game Object instance using `Video.on('unsupported', listener)`.", + "Phaser.GameObjects.Particles.Events.COMPLETE": "The Particle Emitter Complete Event.\n\nThis event is dispatched when the final particle, emitted from a Particle Emitter that\nhas been stopped, dies. Upon receipt of this event you know that no particles are\nstill rendering at this point in time.\n\nListen for it on a Particle Emitter instance using `ParticleEmitter.on('complete', listener)`.", + "Phaser.GameObjects.Particles.Events.DEATH_ZONE": "The Particle Emitter Death Zone Event.\n\nThis event is dispatched when a Death Zone kills a Particle instance.\n\nListen for it on a Particle Emitter instance using `ParticleEmitter.on('deathzone', listener)`.\n\nIf you wish to know when the final particle is killed, see the `COMPLETE` event.", + "Phaser.GameObjects.Particles.Events.EXPLODE": "The Particle Emitter Explode Event.\n\nThis event is dispatched when a Particle Emitter explodes a set of particles.\n\nListen for it on a Particle Emitter instance using `ParticleEmitter.on('explode', listener)`.", + "Phaser.GameObjects.Particles.Events.START": "The Particle Emitter Start Event.\n\nThis event is dispatched when a Particle Emitter starts emission of particles.\n\nListen for it on a Particle Emitter instance using `ParticleEmitter.on('start', listener)`.", + "Phaser.GameObjects.Particles.Events.STOP": "The Particle Emitter Stop Event.\n\nThis event is dispatched when a Particle Emitter is stopped. This can happen either\nwhen you directly call the `ParticleEmitter.stop` method, or if the emitter has\nbeen configured to stop after a set time via the `duration` property, or after a\nset number of particles via the `stopAfter` property.\n\nListen for it on a Particle Emitter instance using `ParticleEmitter.on('stop', listener)`.\n\nNote that just because the emitter has stopped, that doesn't mean there aren't still\nparticles alive and rendering. It just means the emitter has stopped emitting particles.\n\nIf you wish to know when the final particle is killed, see the `COMPLETE` event.", + "Phaser.Input.Events.BOOT": "The Input Plugin Boot Event.\n\nThis internal event is dispatched by the Input Plugin when it boots, signalling to all of its systems to create themselves.", + "Phaser.Input.Events.DESTROY": "The Input Plugin Destroy Event.\n\nThis internal event is dispatched by the Input Plugin when it is destroyed, signalling to all of its systems to destroy themselves.", + "Phaser.Input.Events.DRAG_END": "The Pointer Drag End Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer stops dragging a Game Object.\n\nListen to this event from within a Scene using: `this.input.on('dragend', listener)`.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG_END]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG_END} event instead.", + "Phaser.Input.Events.DRAG_ENTER": "The Pointer Drag Enter Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer drags a Game Object into a Drag Target.\n\nListen to this event from within a Scene using: `this.input.on('dragenter', listener)`.\n\nA Pointer can only drag a single Game Object at once.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG_ENTER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG_ENTER} event instead.", + "Phaser.Input.Events.DRAG": "The Pointer Drag Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer moves while dragging a Game Object.\n\nListen to this event from within a Scene using: `this.input.on('drag', listener)`.\n\nA Pointer can only drag a single Game Object at once.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG} event instead.", + "Phaser.Input.Events.DRAG_LEAVE": "The Pointer Drag Leave Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer drags a Game Object out of a Drag Target.\n\nListen to this event from within a Scene using: `this.input.on('dragleave', listener)`.\n\nA Pointer can only drag a single Game Object at once.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG_LEAVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG_LEAVE} event instead.", + "Phaser.Input.Events.DRAG_OVER": "The Pointer Drag Over Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer drags a Game Object over a Drag Target.\n\nWhen the Game Object first enters the drag target it will emit a `dragenter` event. If it then moves while within\nthe drag target, it will emit this event instead.\n\nListen to this event from within a Scene using: `this.input.on('dragover', listener)`.\n\nA Pointer can only drag a single Game Object at once.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG_OVER} event instead.", + "Phaser.Input.Events.DRAG_START": "The Pointer Drag Start Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer starts to drag any Game Object.\n\nListen to this event from within a Scene using: `this.input.on('dragstart', listener)`.\n\nA Pointer can only drag a single Game Object at once.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DRAG_START]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DRAG_START} event instead.", + "Phaser.Input.Events.DROP": "The Pointer Drop Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer drops a Game Object on a Drag Target.\n\nListen to this event from within a Scene using: `this.input.on('drop', listener)`.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_DROP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DROP} event instead.", + "Phaser.Input.Events.GAMEOBJECT_DOWN": "The Game Object Down Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is pressed down on _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectdown', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_DOWN} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_DOWN}\n2. [GAMEOBJECT_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DOWN}\n3. [POINTER_DOWN]{@linkcode Phaser.Input.Events#event:POINTER_DOWN} or [POINTER_DOWN_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_DOWN_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_DRAG_END": "The Game Object Drag End Event.\n\nThis event is dispatched by an interactive Game Object if a pointer stops dragging it.\n\nListen to this event from a Game Object using: `gameObject.on('dragend', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive](Phaser.GameObjects.GameObject#setInteractive) for more details.", + "Phaser.Input.Events.GAMEOBJECT_DRAG_ENTER": "The Game Object Drag Enter Event.\n\nThis event is dispatched by an interactive Game Object if a pointer drags it into a drag target.\n\nListen to this event from a Game Object using: `gameObject.on('dragenter', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.", + "Phaser.Input.Events.GAMEOBJECT_DRAG": "The Game Object Drag Event.\n\nThis event is dispatched by an interactive Game Object if a pointer moves while dragging it.\n\nListen to this event from a Game Object using: `gameObject.on('drag', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.", + "Phaser.Input.Events.GAMEOBJECT_DRAG_LEAVE": "The Game Object Drag Leave Event.\n\nThis event is dispatched by an interactive Game Object if a pointer drags it out of a drag target.\n\nListen to this event from a Game Object using: `gameObject.on('dragleave', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.", + "Phaser.Input.Events.GAMEOBJECT_DRAG_OVER": "The Game Object Drag Over Event.\n\nThis event is dispatched by an interactive Game Object if a pointer drags it over a drag target.\n\nWhen the Game Object first enters the drag target it will emit a `dragenter` event. If it then moves while within\nthe drag target, it will emit this event instead.\n\nListen to this event from a Game Object using: `gameObject.on('dragover', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.", + "Phaser.Input.Events.GAMEOBJECT_DRAG_START": "The Game Object Drag Start Event.\n\nThis event is dispatched by an interactive Game Object if a pointer starts to drag it.\n\nListen to this event from a Game Object using: `gameObject.on('dragstart', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThere are lots of useful drag related properties that are set within the Game Object when dragging occurs.\nFor example, `gameObject.input.dragStartX`, `dragStartY` and so on.", + "Phaser.Input.Events.GAMEOBJECT_DROP": "The Game Object Drop Event.\n\nThis event is dispatched by an interactive Game Object if a pointer drops it on a Drag Target.\n\nListen to this event from a Game Object using: `gameObject.on('drop', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive and enabled for drag.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.", + "Phaser.Input.Events.GAMEOBJECT_MOVE": "The Game Object Move Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is moved across _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectmove', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_MOVE} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_MOVE}\n2. [GAMEOBJECT_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_MOVE}\n3. [POINTER_MOVE]{@linkcode Phaser.Input.Events#event:POINTER_MOVE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_OUT": "The Game Object Out Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer moves out of _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectout', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OUT} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OUT}\n2. [GAMEOBJECT_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OUT}\n3. [POINTER_OUT]{@linkcode Phaser.Input.Events#event:POINTER_OUT}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.\n\nIf the pointer leaves the game canvas itself, it will not trigger an this event. To handle those cases,\nplease listen for the [GAME_OUT]{@linkcode Phaser.Input.Events#event:GAME_OUT} event.", + "Phaser.Input.Events.GAMEOBJECT_OVER": "The Game Object Over Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer moves over _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectover', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OVER} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OVER}\n2. [GAMEOBJECT_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OVER}\n3. [POINTER_OVER]{@linkcode Phaser.Input.Events#event:POINTER_OVER}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_DOWN": "The Game Object Pointer Down Event.\n\nThis event is dispatched by an interactive Game Object if a pointer is pressed down on it.\n\nListen to this event from a Game Object using: `gameObject.on('pointerdown', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_DOWN}\n2. [GAMEOBJECT_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DOWN}\n3. [POINTER_DOWN]{@linkcode Phaser.Input.Events#event:POINTER_DOWN} or [POINTER_DOWN_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_DOWN_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_MOVE": "The Game Object Pointer Move Event.\n\nThis event is dispatched by an interactive Game Object if a pointer is moved while over it.\n\nListen to this event from a Game Object using: `gameObject.on('pointermove', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_MOVE}\n2. [GAMEOBJECT_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_MOVE}\n3. [POINTER_MOVE]{@linkcode Phaser.Input.Events#event:POINTER_MOVE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_OUT": "The Game Object Pointer Out Event.\n\nThis event is dispatched by an interactive Game Object if a pointer moves out of it.\n\nListen to this event from a Game Object using: `gameObject.on('pointerout', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OUT}\n2. [GAMEOBJECT_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OUT}\n3. [POINTER_OUT]{@linkcode Phaser.Input.Events#event:POINTER_OUT}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.\n\nIf the pointer leaves the game canvas itself, it will not trigger an this event. To handle those cases,\nplease listen for the [GAME_OUT]{@linkcode Phaser.Input.Events#event:GAME_OUT} event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_OVER": "The Game Object Pointer Over Event.\n\nThis event is dispatched by an interactive Game Object if a pointer moves over it.\n\nListen to this event from a Game Object using: `gameObject.on('pointerover', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OVER}\n2. [GAMEOBJECT_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OVER}\n3. [POINTER_OVER]{@linkcode Phaser.Input.Events#event:POINTER_OVER}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_UP": "The Game Object Pointer Up Event.\n\nThis event is dispatched by an interactive Game Object if a pointer is released while over it.\n\nListen to this event from a Game Object using: `gameObject.on('pointerup', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_UP}\n2. [GAMEOBJECT_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_UP}\n3. [POINTER_UP]{@linkcode Phaser.Input.Events#event:POINTER_UP} or [POINTER_UP_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_UP_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_POINTER_WHEEL": "The Game Object Pointer Wheel Event.\n\nThis event is dispatched by an interactive Game Object if a pointer has its wheel moved while over it.\n\nListen to this event from a Game Object using: `gameObject.on('wheel', listener)`.\nNote that the scope of the listener is automatically set to be the Game Object instance itself.\n\nTo receive this event, the Game Object must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_WHEEL}\n2. [GAMEOBJECT_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_WHEEL}\n3. [POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:POINTER_WHEEL}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_UP": "The Game Object Up Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is released while over _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectup', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_UP} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_UP}\n2. [GAMEOBJECT_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_UP}\n3. [POINTER_UP]{@linkcode Phaser.Input.Events#event:POINTER_UP} or [POINTER_UP_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_UP_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAMEOBJECT_WHEEL": "The Game Object Wheel Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer has its wheel moved while over _any_ interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('gameobjectwheel', listener)`.\n\nTo receive this event, the Game Objects must have been set as interactive.\nSee [GameObject.setInteractive]{@link Phaser.GameObjects.GameObject#setInteractive} for more details.\n\nTo listen for this event from a _specific_ Game Object, use the [GAMEOBJECT_POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_WHEEL} event instead.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_WHEEL}\n2. [GAMEOBJECT_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_WHEEL}\n3. [POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:POINTER_WHEEL}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.GAME_OUT": "The Input Plugin Game Out Event.\n\nThis event is dispatched by the Input Plugin if the active pointer leaves the game canvas and is now\noutside of it, elsewhere on the web page.\n\nListen to this event from within a Scene using: `this.input.on('gameout', listener)`.", + "Phaser.Input.Events.GAME_OVER": "The Input Plugin Game Over Event.\n\nThis event is dispatched by the Input Plugin if the active pointer enters the game canvas and is now\nover of it, having previously been elsewhere on the web page.\n\nListen to this event from within a Scene using: `this.input.on('gameover', listener)`.", + "Phaser.Input.Events.MANAGER_BOOT": "The Input Manager Boot Event.\n\nThis internal event is dispatched by the Input Manager when it boots.", + "Phaser.Input.Events.MANAGER_PROCESS": "The Input Manager Process Event.\n\nThis internal event is dispatched by the Input Manager when not using the legacy queue system,\nand it wants the Input Plugins to update themselves.", + "Phaser.Input.Events.MANAGER_UPDATE": "The Input Manager Update Event.\n\nThis internal event is dispatched by the Input Manager as part of its update step.", + "Phaser.Input.Events.POINTERLOCK_CHANGE": "The Input Manager Pointer Lock Change Event.\n\nThis event is dispatched by the Input Manager when it is processing a native Pointer Lock Change DOM Event.", + "Phaser.Input.Events.POINTER_DOWN": "The Pointer Down Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is pressed down anywhere.\n\nListen to this event from within a Scene using: `this.input.on('pointerdown', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_DOWN}\n2. [GAMEOBJECT_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DOWN}\n3. [POINTER_DOWN]{@linkcode Phaser.Input.Events#event:POINTER_DOWN} or [POINTER_DOWN_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_DOWN_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_DOWN_OUTSIDE": "The Pointer Down Outside Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is pressed down anywhere outside of the game canvas.\n\nListen to this event from within a Scene using: `this.input.on('pointerdownoutside', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_DOWN}\n2. [GAMEOBJECT_DOWN]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_DOWN}\n3. [POINTER_DOWN]{@linkcode Phaser.Input.Events#event:POINTER_DOWN} or [POINTER_DOWN_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_DOWN_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_MOVE": "The Pointer Move Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is moved anywhere.\n\nListen to this event from within a Scene using: `this.input.on('pointermove', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_MOVE}\n2. [GAMEOBJECT_MOVE]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_MOVE}\n3. [POINTER_MOVE]{@linkcode Phaser.Input.Events#event:POINTER_MOVE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_OUT": "The Pointer Out Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer moves out of any interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('pointerout', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OUT}\n2. [GAMEOBJECT_OUT]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OUT}\n3. [POINTER_OUT]{@linkcode Phaser.Input.Events#event:POINTER_OUT}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.\n\nIf the pointer leaves the game canvas itself, it will not trigger an this event. To handle those cases,\nplease listen for the [GAME_OUT]{@linkcode Phaser.Input.Events#event:GAME_OUT} event.", + "Phaser.Input.Events.POINTER_OVER": "The Pointer Over Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer moves over any interactive Game Object.\n\nListen to this event from within a Scene using: `this.input.on('pointerover', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_OVER}\n2. [GAMEOBJECT_OVER]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_OVER}\n3. [POINTER_OVER]{@linkcode Phaser.Input.Events#event:POINTER_OVER}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_UP": "The Pointer Up Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is released anywhere.\n\nListen to this event from within a Scene using: `this.input.on('pointerup', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_UP}\n2. [GAMEOBJECT_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_UP}\n3. [POINTER_UP]{@linkcode Phaser.Input.Events#event:POINTER_UP} or [POINTER_UP_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_UP_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_UP_OUTSIDE": "The Pointer Up Outside Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer is released anywhere outside of the game canvas.\n\nListen to this event from within a Scene using: `this.input.on('pointerupoutside', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_UP}\n2. [GAMEOBJECT_UP]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_UP}\n3. [POINTER_UP]{@linkcode Phaser.Input.Events#event:POINTER_UP} or [POINTER_UP_OUTSIDE]{@linkcode Phaser.Input.Events#event:POINTER_UP_OUTSIDE}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.POINTER_WHEEL": "The Pointer Wheel Input Event.\n\nThis event is dispatched by the Input Plugin belonging to a Scene if a pointer has its wheel updated.\n\nListen to this event from within a Scene using: `this.input.on('wheel', listener)`.\n\nThe event hierarchy is as follows:\n\n1. [GAMEOBJECT_POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_POINTER_WHEEL}\n2. [GAMEOBJECT_WHEEL]{@linkcode Phaser.Input.Events#event:GAMEOBJECT_WHEEL}\n3. [POINTER_WHEEL]{@linkcode Phaser.Input.Events#event:POINTER_WHEEL}\n\nWith the top event being dispatched first and then flowing down the list. Note that higher-up event handlers can stop\nthe propagation of this event.", + "Phaser.Input.Events.PRE_UPDATE": "The Input Plugin Pre-Update Event.\n\nThis internal event is dispatched by the Input Plugin at the start of its `preUpdate` method.\nThis hook is designed specifically for input plugins, but can also be listened to from user-land code.", + "Phaser.Input.Events.SHUTDOWN": "The Input Plugin Shutdown Event.\n\nThis internal event is dispatched by the Input Plugin when it shuts down, signalling to all of its systems to shut themselves down.", + "Phaser.Input.Events.START": "The Input Plugin Start Event.\n\nThis internal event is dispatched by the Input Plugin when it has finished setting-up,\nsignalling to all of its internal systems to start.", + "Phaser.Input.Events.UPDATE": "The Input Plugin Update Event.\n\nThis internal event is dispatched by the Input Plugin at the start of its `update` method.\nThis hook is designed specifically for input plugins, but can also be listened to from user-land code.", + "Phaser.Input.Gamepad.Events.BUTTON_DOWN": "The Gamepad Button Down Event.\n\nThis event is dispatched by the Gamepad Plugin when a button has been pressed on any active Gamepad.\n\nListen to this event from within a Scene using: `this.input.gamepad.on('down', listener)`.\n\nYou can also listen for a DOWN event from a Gamepad instance. See the [GAMEPAD_BUTTON_DOWN]{@linkcode Phaser.Input.Gamepad.Events#event:GAMEPAD_BUTTON_DOWN} event for details.", + "Phaser.Input.Gamepad.Events.BUTTON_UP": "The Gamepad Button Up Event.\n\nThis event is dispatched by the Gamepad Plugin when a button has been released on any active Gamepad.\n\nListen to this event from within a Scene using: `this.input.gamepad.on('up', listener)`.\n\nYou can also listen for an UP event from a Gamepad instance. See the [GAMEPAD_BUTTON_UP]{@linkcode Phaser.Input.Gamepad.Events#event:GAMEPAD_BUTTON_UP} event for details.", + "Phaser.Input.Gamepad.Events.CONNECTED": "The Gamepad Connected Event.\n\nThis event is dispatched by the Gamepad Plugin when a Gamepad has been connected.\n\nListen to this event from within a Scene using: `this.input.gamepad.once('connected', listener)`.\n\nNote that the browser may require you to press a button on a gamepad before it will allow you to access it,\nthis is for security reasons. However, it may also trust the page already, in which case you won't get the\n'connected' event and instead should check `GamepadPlugin.total` to see if it thinks there are any gamepads\nalready connected.", + "Phaser.Input.Gamepad.Events.DISCONNECTED": "The Gamepad Disconnected Event.\n\nThis event is dispatched by the Gamepad Plugin when a Gamepad has been disconnected.\n\nListen to this event from within a Scene using: `this.input.gamepad.once('disconnected', listener)`.", + "Phaser.Input.Gamepad.Events.GAMEPAD_BUTTON_DOWN": "The Gamepad Button Down Event.\n\nThis event is dispatched by a Gamepad instance when a button has been pressed on it.\n\nListen to this event from a Gamepad instance. Once way to get this is from the `pad1`, `pad2`, etc properties on the Gamepad Plugin:\n`this.input.gamepad.pad1.on('down', listener)`.\n\nNote that you will not receive any Gamepad button events until the browser considers the Gamepad as being 'connected'.\n\nYou can also listen for a DOWN event from the Gamepad Plugin. See the [BUTTON_DOWN]{@linkcode Phaser.Input.Gamepad.Events#event:BUTTON_DOWN} event for details.", + "Phaser.Input.Gamepad.Events.GAMEPAD_BUTTON_UP": "The Gamepad Button Up Event.\n\nThis event is dispatched by a Gamepad instance when a button has been released on it.\n\nListen to this event from a Gamepad instance. Once way to get this is from the `pad1`, `pad2`, etc properties on the Gamepad Plugin:\n`this.input.gamepad.pad1.on('up', listener)`.\n\nNote that you will not receive any Gamepad button events until the browser considers the Gamepad as being 'connected'.\n\nYou can also listen for an UP event from the Gamepad Plugin. See the [BUTTON_UP]{@linkcode Phaser.Input.Gamepad.Events#event:BUTTON_UP} event for details.", + "Phaser.Input.Keyboard.Events.ANY_KEY_DOWN": "The Global Key Down Event.\n\nThis event is dispatched by the Keyboard Plugin when any key on the keyboard is pressed down.\n\nListen to this event from within a Scene using: `this.input.keyboard.on('keydown', listener)`.\n\nYou can also listen for a specific key being pressed. See [Keyboard.Events.KEY_DOWN]{@linkcode Phaser.Input.Keyboard.Events#event:KEY_DOWN} for details.\n\nFinally, you can create Key objects, which you can also listen for events from. See [Keyboard.Events.DOWN]{@linkcode Phaser.Input.Keyboard.Events#event:DOWN} for details.\n\n_Note_: Many keyboards are unable to process certain combinations of keys due to hardware limitations known as ghosting.\nRead [this article on ghosting]{@link http://www.html5gamedevs.com/topic/4876-impossible-to-use-more-than-2-keyboard-input-buttons-at-the-same-time/} for details.\n\nAlso, please be aware that some browser extensions can disable or override Phaser keyboard handling.\nFor example, the Chrome extension vimium is known to disable Phaser from using the D key, while EverNote disables the backtick key.\nThere are others. So, please check your extensions if you find you have specific keys that don't work.", + "Phaser.Input.Keyboard.Events.ANY_KEY_UP": "The Global Key Up Event.\n\nThis event is dispatched by the Keyboard Plugin when any key on the keyboard is released.\n\nListen to this event from within a Scene using: `this.input.keyboard.on('keyup', listener)`.\n\nYou can also listen for a specific key being released. See [Keyboard.Events.KEY_UP]{@linkcode Phaser.Input.Keyboard.Events#event:KEY_UP} for details.\n\nFinally, you can create Key objects, which you can also listen for events from. See [Keyboard.Events.UP]{@linkcode Phaser.Input.Keyboard.Events#event:UP} for details.", + "Phaser.Input.Keyboard.Events.COMBO_MATCH": "The Key Combo Match Event.\n\nThis event is dispatched by the Keyboard Plugin when a [Key Combo]{@link Phaser.Input.Keyboard.KeyCombo} is matched.\n\nListen for this event from the Key Plugin after a combo has been created:\n\n```javascript\nthis.input.keyboard.createCombo([ 38, 38, 40, 40, 37, 39, 37, 39, 66, 65, 13 ], { resetOnMatch: true });\n\nthis.input.keyboard.on('keycombomatch', function (event) {\n console.log('Konami Code entered!');\n});\n```", + "Phaser.Input.Keyboard.Events.DOWN": "The Key Down Event.\n\nThis event is dispatched by a [Key]{@link Phaser.Input.Keyboard.Key} object when it is pressed.\n\nListen for this event from the Key object instance directly:\n\n```javascript\nvar spaceBar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);\n\nspaceBar.on('down', listener)\n```\n\nYou can also create a generic 'global' listener. See [Keyboard.Events.ANY_KEY_DOWN]{@linkcode Phaser.Input.Keyboard.Events#event:ANY_KEY_DOWN} for details.", + "Phaser.Input.Keyboard.Events.KEY_DOWN": "The Key Down Event.\n\nThis event is dispatched by the Keyboard Plugin when any key on the keyboard is pressed down.\n\nUnlike the `ANY_KEY_DOWN` event, this one has a special dynamic event name. For example, to listen for the `A` key being pressed\nuse the following from within a Scene: `this.input.keyboard.on('keydown-A', listener)`. You can replace the `-A` part of the event\nname with any valid [Key Code string]{@link Phaser.Input.Keyboard.KeyCodes}. For example, this will listen for the space bar:\n`this.input.keyboard.on('keydown-SPACE', listener)`.\n\nYou can also create a generic 'global' listener. See [Keyboard.Events.ANY_KEY_DOWN]{@linkcode Phaser.Input.Keyboard.Events#event:ANY_KEY_DOWN} for details.\n\nFinally, you can create Key objects, which you can also listen for events from. See [Keyboard.Events.DOWN]{@linkcode Phaser.Input.Keyboard.Events#event:DOWN} for details.\n\n_Note_: Many keyboards are unable to process certain combinations of keys due to hardware limitations known as ghosting.\nRead [this article on ghosting]{@link http://www.html5gamedevs.com/topic/4876-impossible-to-use-more-than-2-keyboard-input-buttons-at-the-same-time/} for details.\n\nAlso, please be aware that some browser extensions can disable or override Phaser keyboard handling.\nFor example, the Chrome extension vimium is known to disable Phaser from using the D key, while EverNote disables the backtick key.\nThere are others. So, please check your extensions if you find you have specific keys that don't work.", + "Phaser.Input.Keyboard.Events.KEY_UP": "The Key Up Event.\n\nThis event is dispatched by the Keyboard Plugin when any key on the keyboard is released.\n\nUnlike the `ANY_KEY_UP` event, this one has a special dynamic event name. For example, to listen for the `A` key being released\nuse the following from within a Scene: `this.input.keyboard.on('keyup-A', listener)`. You can replace the `-A` part of the event\nname with any valid [Key Code string]{@link Phaser.Input.Keyboard.KeyCodes}. For example, this will listen for the space bar:\n`this.input.keyboard.on('keyup-SPACE', listener)`.\n\nYou can also create a generic 'global' listener. See [Keyboard.Events.ANY_KEY_UP]{@linkcode Phaser.Input.Keyboard.Events#event:ANY_KEY_UP} for details.\n\nFinally, you can create Key objects, which you can also listen for events from. See [Keyboard.Events.UP]{@linkcode Phaser.Input.Keyboard.Events#event:UP} for details.", + "Phaser.Input.Keyboard.Events.UP": "The Key Up Event.\n\nThis event is dispatched by a [Key]{@link Phaser.Input.Keyboard.Key} object when it is released.\n\nListen for this event from the Key object instance directly:\n\n```javascript\nvar spaceBar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);\n\nspaceBar.on('up', listener)\n```\n\nYou can also create a generic 'global' listener. See [Keyboard.Events.ANY_KEY_UP]{@linkcode Phaser.Input.Keyboard.Events#event:ANY_KEY_UP} for details.", + "Phaser.Loader.Events.ADD": "The Loader Plugin Add File Event.\n\nThis event is dispatched when a new file is successfully added to the Loader and placed into the load queue.\n\nListen to it from a Scene using: `this.load.on('addfile', listener)`.\n\nIf you add lots of files to a Loader from a `preload` method, it will dispatch this event for each one of them.", + "Phaser.Loader.Events.COMPLETE": "The Loader Plugin Complete Event.\n\nThis event is dispatched when the Loader has fully processed everything in the load queue.\nBy this point every loaded file will now be in its associated cache and ready for use.\n\nListen to it from a Scene using: `this.load.on('complete', listener)`.", + "Phaser.Loader.Events.FILE_COMPLETE": "The File Load Complete Event.\n\nThis event is dispatched by the Loader Plugin when _any_ file in the queue finishes loading.\n\nListen to it from a Scene using: `this.load.on('filecomplete', listener)`.\n\nMake sure you remove this listener when you have finished, or it will continue to fire if the Scene reloads.\n\nYou can also listen for the completion of a specific file. See the [FILE_KEY_COMPLETE]{@linkcode Phaser.Loader.Events#event:FILE_KEY_COMPLETE} event.", + "Phaser.Loader.Events.FILE_KEY_COMPLETE": "The File Load Complete Event.\n\nThis event is dispatched by the Loader Plugin when any file in the queue finishes loading.\n\nIt uses a special dynamic event name constructed from the key and type of the file.\n\nFor example, if you have loaded an `image` with a key of `monster`, you can listen for it\nusing the following:\n\n```javascript\nthis.load.on('filecomplete-image-monster', function (key, type, data) {\n // Your handler code\n});\n```\n\nOr, if you have loaded a texture `atlas` with a key of `Level1`:\n\n```javascript\nthis.load.on('filecomplete-atlasjson-Level1', function (key, type, data) {\n // Your handler code\n});\n```\n\nOr, if you have loaded a sprite sheet with a key of `Explosion` and a prefix of `GAMEOVER`:\n\n```javascript\nthis.load.on('filecomplete-spritesheet-GAMEOVERExplosion', function (key, type, data) {\n // Your handler code\n});\n```\n\nMake sure you remove your listeners when you have finished, or they will continue to fire if the Scene reloads.\n\nYou can also listen for the generic completion of files. See the [FILE_COMPLETE]{@linkcode Phaser.Loader.Events#event:FILE_COMPLETE} event.", + "Phaser.Loader.Events.FILE_LOAD_ERROR": "The File Load Error Event.\n\nThis event is dispatched by the Loader Plugin when a file fails to load.\n\nListen to it from a Scene using: `this.load.on('loaderror', listener)`.", + "Phaser.Loader.Events.FILE_LOAD": "The File Load Event.\n\nThis event is dispatched by the Loader Plugin when a file finishes loading,\nbut _before_ it is processed and added to the internal Phaser caches.\n\nListen to it from a Scene using: `this.load.on('load', listener)`.", + "Phaser.Loader.Events.FILE_PROGRESS": "The File Load Progress Event.\n\nThis event is dispatched by the Loader Plugin during the load of a file, if the browser receives a DOM ProgressEvent and\nthe `lengthComputable` event property is true. Depending on the size of the file and browser in use, this may, or may not happen.\n\nListen to it from a Scene using: `this.load.on('fileprogress', listener)`.", + "Phaser.Loader.Events.POST_PROCESS": "The Loader Plugin Post Process Event.\n\nThis event is dispatched by the Loader Plugin when the Loader has finished loading everything in the load queue.\nIt is dispatched before the internal lists are cleared and each File is destroyed.\n\nUse this hook to perform any last minute processing of files that can only happen once the\nLoader has completed, but prior to it emitting the `complete` event.\n\nListen to it from a Scene using: `this.load.on('postprocess', listener)`.", + "Phaser.Loader.Events.PROGRESS": "The Loader Plugin Progress Event.\n\nThis event is dispatched when the Loader updates its load progress, typically as a result of a file having completed loading.\n\nListen to it from a Scene using: `this.load.on('progress', listener)`.", + "Phaser.Loader.Events.START": "The Loader Plugin Start Event.\n\nThis event is dispatched when the Loader starts running. At this point load progress is zero.\n\nThis event is dispatched even if there aren't any files in the load queue.\n\nListen to it from a Scene using: `this.load.on('start', listener)`.", + "Phaser.Physics.Arcade.Events.COLLIDE": "The Arcade Physics World Collide Event.\n\nThis event is dispatched by an Arcade Physics World instance if two bodies collide _and_ at least\none of them has their [onCollide]{@link Phaser.Physics.Arcade.Body#onCollide} property set to `true`.\n\nIt provides an alternative means to handling collide events rather than using the callback approach.\n\nListen to it from a Scene using: `this.physics.world.on('collide', listener)`.\n\nPlease note that 'collide' and 'overlap' are two different things in Arcade Physics.", + "Phaser.Physics.Arcade.Events.OVERLAP": "The Arcade Physics World Overlap Event.\n\nThis event is dispatched by an Arcade Physics World instance if two bodies overlap _and_ at least\none of them has their [onOverlap]{@link Phaser.Physics.Arcade.Body#onOverlap} property set to `true`.\n\nIt provides an alternative means to handling overlap events rather than using the callback approach.\n\nListen to it from a Scene using: `this.physics.world.on('overlap', listener)`.\n\nPlease note that 'collide' and 'overlap' are two different things in Arcade Physics.", + "Phaser.Physics.Arcade.Events.PAUSE": "The Arcade Physics World Pause Event.\n\nThis event is dispatched by an Arcade Physics World instance when it is paused.\n\nListen to it from a Scene using: `this.physics.world.on('pause', listener)`.", + "Phaser.Physics.Arcade.Events.RESUME": "The Arcade Physics World Resume Event.\n\nThis event is dispatched by an Arcade Physics World instance when it resumes from a paused state.\n\nListen to it from a Scene using: `this.physics.world.on('resume', listener)`.", + "Phaser.Physics.Arcade.Events.TILE_COLLIDE": "The Arcade Physics Tile Collide Event.\n\nThis event is dispatched by an Arcade Physics World instance if a body collides with a Tile _and_\nhas its [onCollide]{@link Phaser.Physics.Arcade.Body#onCollide} property set to `true`.\n\nIt provides an alternative means to handling collide events rather than using the callback approach.\n\nListen to it from a Scene using: `this.physics.world.on('tilecollide', listener)`.\n\nPlease note that 'collide' and 'overlap' are two different things in Arcade Physics.", + "Phaser.Physics.Arcade.Events.TILE_OVERLAP": "The Arcade Physics Tile Overlap Event.\n\nThis event is dispatched by an Arcade Physics World instance if a body overlaps with a Tile _and_\nhas its [onOverlap]{@link Phaser.Physics.Arcade.Body#onOverlap} property set to `true`.\n\nIt provides an alternative means to handling overlap events rather than using the callback approach.\n\nListen to it from a Scene using: `this.physics.world.on('tileoverlap', listener)`.\n\nPlease note that 'collide' and 'overlap' are two different things in Arcade Physics.", + "Phaser.Physics.Arcade.Events.WORLD_BOUNDS": "The Arcade Physics World Bounds Event.\n\nThis event is dispatched by an Arcade Physics World instance if a body makes contact with the world bounds _and_\nit has its [onWorldBounds]{@link Phaser.Physics.Arcade.Body#onWorldBounds} property set to `true`.\n\nIt provides an alternative means to handling collide events rather than using the callback approach.\n\nListen to it from a Scene using: `this.physics.world.on('worldbounds', listener)`.", + "Phaser.Physics.Arcade.Events.WORLD_STEP": "The Arcade Physics World Step Event.\n\nThis event is dispatched by an Arcade Physics World instance whenever a physics step is run.\nIt is emitted _after_ the bodies and colliders have been updated.\n\nIn high framerate settings this can be multiple times per game frame.\n\nListen to it from a Scene using: `this.physics.world.on('worldstep', listener)`.", + "Phaser.Physics.Matter.Events.AFTER_ADD": "The Matter Physics After Add Event.\n\nThis event is dispatched by a Matter Physics World instance at the end of the process when a new Body\nor Constraint has just been added to the world.\n\nListen to it from a Scene using: `this.matter.world.on('afteradd', listener)`.", + "Phaser.Physics.Matter.Events.AFTER_REMOVE": "The Matter Physics After Remove Event.\n\nThis event is dispatched by a Matter Physics World instance at the end of the process when a\nBody or Constraint was removed from the world.\n\nListen to it from a Scene using: `this.matter.world.on('afterremove', listener)`.", + "Phaser.Physics.Matter.Events.AFTER_UPDATE": "The Matter Physics After Update Event.\n\nThis event is dispatched by a Matter Physics World instance after the engine has updated and all collision events have resolved.\n\nListen to it from a Scene using: `this.matter.world.on('afterupdate', listener)`.", + "Phaser.Physics.Matter.Events.BEFORE_ADD": "The Matter Physics Before Add Event.\n\nThis event is dispatched by a Matter Physics World instance at the start of the process when a new Body\nor Constraint is being added to the world.\n\nListen to it from a Scene using: `this.matter.world.on('beforeadd', listener)`.", + "Phaser.Physics.Matter.Events.BEFORE_REMOVE": "The Matter Physics Before Remove Event.\n\nThis event is dispatched by a Matter Physics World instance at the start of the process when a\nBody or Constraint is being removed from the world.\n\nListen to it from a Scene using: `this.matter.world.on('beforeremove', listener)`.", + "Phaser.Physics.Matter.Events.BEFORE_UPDATE": "The Matter Physics Before Update Event.\n\nThis event is dispatched by a Matter Physics World instance right before all the collision processing takes place.\n\nListen to it from a Scene using: `this.matter.world.on('beforeupdate', listener)`.", + "Phaser.Physics.Matter.Events.COLLISION_ACTIVE": "The Matter Physics Collision Active Event.\n\nThis event is dispatched by a Matter Physics World instance after the engine has updated.\nIt provides a list of all pairs that are colliding in the current tick (if any).\n\nListen to it from a Scene using: `this.matter.world.on('collisionactive', listener)`.", + "Phaser.Physics.Matter.Events.COLLISION_END": "The Matter Physics Collision End Event.\n\nThis event is dispatched by a Matter Physics World instance after the engine has updated.\nIt provides a list of all pairs that have finished colliding in the current tick (if any).\n\nListen to it from a Scene using: `this.matter.world.on('collisionend', listener)`.", + "Phaser.Physics.Matter.Events.COLLISION_START": "The Matter Physics Collision Start Event.\n\nThis event is dispatched by a Matter Physics World instance after the engine has updated.\nIt provides a list of all pairs that have started to collide in the current tick (if any).\n\nListen to it from a Scene using: `this.matter.world.on('collisionstart', listener)`.", + "Phaser.Physics.Matter.Events.DRAG_END": "The Matter Physics Drag End Event.\n\nThis event is dispatched by a Matter Physics World instance when a Pointer Constraint\nstops dragging a body.\n\nListen to it from a Scene using: `this.matter.world.on('dragend', listener)`.", + "Phaser.Physics.Matter.Events.DRAG": "The Matter Physics Drag Event.\n\nThis event is dispatched by a Matter Physics World instance when a Pointer Constraint\nis actively dragging a body. It is emitted each time the pointer moves.\n\nListen to it from a Scene using: `this.matter.world.on('drag', listener)`.", + "Phaser.Physics.Matter.Events.DRAG_START": "The Matter Physics Drag Start Event.\n\nThis event is dispatched by a Matter Physics World instance when a Pointer Constraint\nstarts dragging a body.\n\nListen to it from a Scene using: `this.matter.world.on('dragstart', listener)`.", + "Phaser.Physics.Matter.Events.PAUSE": "The Matter Physics World Pause Event.\n\nThis event is dispatched by an Matter Physics World instance when it is paused.\n\nListen to it from a Scene using: `this.matter.world.on('pause', listener)`.", + "Phaser.Physics.Matter.Events.RESUME": "The Matter Physics World Resume Event.\n\nThis event is dispatched by an Matter Physics World instance when it resumes from a paused state.\n\nListen to it from a Scene using: `this.matter.world.on('resume', listener)`.", + "Phaser.Physics.Matter.Events.SLEEP_END": "The Matter Physics Sleep End Event.\n\nThis event is dispatched by a Matter Physics World instance when a Body stop sleeping.\n\nListen to it from a Scene using: `this.matter.world.on('sleepend', listener)`.", + "Phaser.Physics.Matter.Events.SLEEP_START": "The Matter Physics Sleep Start Event.\n\nThis event is dispatched by a Matter Physics World instance when a Body goes to sleep.\n\nListen to it from a Scene using: `this.matter.world.on('sleepstart', listener)`.", + "Phaser.Renderer.Events.POST_RENDER": "The Post-Render Event.\n\nThis event is dispatched by the Renderer when all rendering, for all cameras in all Scenes,\nhas completed, but before any pending snap shots have been taken.", + "Phaser.Renderer.Events.PRE_RENDER": "The Pre-Render Event.\n\nThis event is dispatched by the Phaser Renderer. This happens right at the start of the render\nprocess, after the context has been cleared, the scissors enabled (WebGL only) and everything has been\nreset ready for the render.", + "Phaser.Renderer.Events.RENDER": "The Render Event.\n\nThis event is dispatched by the Phaser Renderer for every camera in every Scene.\n\nIt is dispatched before any of the children in the Scene have been rendered.", + "Phaser.Renderer.Events.RESIZE": "The Renderer Resize Event.\n\nThis event is dispatched by the Phaser Renderer when it is resized, usually as a result\nof the Scale Manager resizing.", + "Phaser.Renderer.WebGL.Pipelines.Events.AFTER_FLUSH": "The WebGLPipeline After Flush Event.\n\nThis event is dispatched by a WebGLPipeline right after it has issued a drawArrays command\nand cleared its vertex count.", + "Phaser.Renderer.WebGL.Pipelines.Events.BEFORE_FLUSH": "The WebGLPipeline Before Flush Event.\n\nThis event is dispatched by a WebGLPipeline right before it is about to\nflush and issue a bufferData and drawArrays command.", + "Phaser.Renderer.WebGL.Pipelines.Events.BIND": "The WebGLPipeline Bind Event.\n\nThis event is dispatched by a WebGLPipeline when it is bound by the Pipeline Manager.", + "Phaser.Renderer.WebGL.Pipelines.Events.BOOT": "The WebGLPipeline Boot Event.\n\nThis event is dispatched by a WebGLPipeline when it has completed its `boot` phase.", + "Phaser.Renderer.WebGL.Pipelines.Events.DESTROY": "The WebGLPipeline Destroy Event.\n\nThis event is dispatched by a WebGLPipeline when it is starting its destroy process.", + "Phaser.Renderer.WebGL.Pipelines.Events.REBIND": "The WebGLPipeline ReBind Event.\n\nThis event is dispatched by a WebGLPipeline when it is re-bound by the Pipeline Manager.", + "Phaser.Renderer.WebGL.Pipelines.Events.RESIZE": "The WebGLPipeline Resize Event.\n\nThis event is dispatched by a WebGLPipeline when it is resized, usually as a result\nof the Renderer resizing.", + "Phaser.Scale.Events.ENTER_FULLSCREEN": "The Scale Manager has successfully entered fullscreen mode.", + "Phaser.Scale.Events.FULLSCREEN_FAILED": "The Scale Manager tried to enter fullscreen mode but failed.", + "Phaser.Scale.Events.FULLSCREEN_UNSUPPORTED": "The Scale Manager tried to enter fullscreen mode, but it is unsupported by the browser.", + "Phaser.Scale.Events.LEAVE_FULLSCREEN": "The Scale Manager was in fullscreen mode, but has since left, either directly via game code,\nor via a user gestured, such as pressing the ESC key.", + "Phaser.Scale.Events.ORIENTATION_CHANGE": "The Scale Manager Orientation Change Event.\n\nThis event is dispatched whenever the Scale Manager detects an orientation change event from the browser.", + "Phaser.Scale.Events.RESIZE": "The Scale Manager Resize Event.\n\nThis event is dispatched whenever the Scale Manager detects a resize event from the browser.\nIt sends three parameters to the callback, each of them being Size components. You can read\nthe `width`, `height`, `aspectRatio` and other properties of these components to help with\nscaling your own game content.", + "Phaser.Scenes.Events.ADDED_TO_SCENE": "The Game Object Added to Scene Event.\n\nThis event is dispatched when a Game Object is added to a Scene.\n\nListen for it from a Scene using `this.events.on('addedtoscene', listener)`.", + "Phaser.Scenes.Events.BOOT": "The Scene Systems Boot Event.\n\nThis event is dispatched by a Scene during the Scene Systems boot process. Primarily used by Scene Plugins.\n\nListen to it from a Scene using `this.events.on('boot', listener)`.", + "Phaser.Scenes.Events.CREATE": "The Scene Create Event.\n\nThis event is dispatched by a Scene after it has been created by the Scene Manager.\n\nIf a Scene has a `create` method then this event is emitted _after_ that has run.\n\nIf there is a transition, this event will be fired after the `TRANSITION_START` event.\n\nListen to it from a Scene using `this.events.on('create', listener)`.", + "Phaser.Scenes.Events.DESTROY": "The Scene Systems Destroy Event.\n\nThis event is dispatched by a Scene during the Scene Systems destroy process.\n\nListen to it from a Scene using `this.events.on('destroy', listener)`.\n\nYou should destroy any resources that may be in use by your Scene in this event handler.", + "Phaser.Scenes.Events.PAUSE": "The Scene Systems Pause Event.\n\nThis event is dispatched by a Scene when it is paused, either directly via the `pause` method, or as an\naction from another Scene.\n\nListen to it from a Scene using `this.events.on('pause', listener)`.", + "Phaser.Scenes.Events.POST_UPDATE": "The Scene Systems Post Update Event.\n\nThis event is dispatched by a Scene during the main game loop step.\n\nThe event flow for a single step of a Scene is as follows:\n\n1. [PRE_UPDATE]{@linkcode Phaser.Scenes.Events#event:PRE_UPDATE}\n2. [UPDATE]{@linkcode Phaser.Scenes.Events#event:UPDATE}\n3. The `Scene.update` method is called, if it exists\n4. [POST_UPDATE]{@linkcode Phaser.Scenes.Events#event:POST_UPDATE}\n5. [PRE_RENDER]{@linkcode Phaser.Scenes.Events#event:PRE_RENDER}\n6. [RENDER]{@linkcode Phaser.Scenes.Events#event:RENDER}\n\nListen to it from a Scene using `this.events.on('postupdate', listener)`.\n\nA Scene will only run its step if it is active.", + "Phaser.Scenes.Events.PRE_RENDER": "The Scene Systems Pre-Render Event.\n\nThis event is dispatched by a Scene during the main game loop step.\n\nThe event flow for a single step of a Scene is as follows:\n\n1. [PRE_UPDATE]{@linkcode Phaser.Scenes.Events#event:PRE_UPDATE}\n2. [UPDATE]{@linkcode Phaser.Scenes.Events#event:UPDATE}\n3. The `Scene.update` method is called, if it exists\n4. [POST_UPDATE]{@linkcode Phaser.Scenes.Events#event:POST_UPDATE}\n5. [PRE_RENDER]{@linkcode Phaser.Scenes.Events#event:PRE_RENDER}\n6. [RENDER]{@linkcode Phaser.Scenes.Events#event:RENDER}\n\nListen to this event from a Scene using `this.events.on('prerender', listener)`.\n\nA Scene will only render if it is visible.\n\nThis event is dispatched after the Scene Display List is sorted and before the Scene is rendered.", + "Phaser.Scenes.Events.PRE_UPDATE": "The Scene Systems Pre Update Event.\n\nThis event is dispatched by a Scene during the main game loop step.\n\nThe event flow for a single step of a Scene is as follows:\n\n1. [PRE_UPDATE]{@linkcode Phaser.Scenes.Events#event:PRE_UPDATE}\n2. [UPDATE]{@linkcode Phaser.Scenes.Events#event:UPDATE}\n3. The `Scene.update` method is called, if it exists\n4. [POST_UPDATE]{@linkcode Phaser.Scenes.Events#event:POST_UPDATE}\n5. [PRE_RENDER]{@linkcode Phaser.Scenes.Events#event:PRE_RENDER}\n6. [RENDER]{@linkcode Phaser.Scenes.Events#event:RENDER}\n\nListen to it from a Scene using `this.events.on('preupdate', listener)`.\n\nA Scene will only run its step if it is active.", + "Phaser.Scenes.Events.READY": "The Scene Systems Ready Event.\n\nThis event is dispatched by a Scene during the Scene Systems start process.\nBy this point in the process the Scene is now fully active and rendering.\nThis event is meant for your game code to use, as all plugins have responded to the earlier 'start' event.\n\nListen to it from a Scene using `this.events.on('ready', listener)`.", + "Phaser.Scenes.Events.REMOVED_FROM_SCENE": "The Game Object Removed from Scene Event.\n\nThis event is dispatched when a Game Object is removed from a Scene.\n\nListen for it from a Scene using `this.events.on('removedfromscene', listener)`.", + "Phaser.Scenes.Events.RENDER": "The Scene Systems Render Event.\n\nThis event is dispatched by a Scene during the main game loop step.\n\nThe event flow for a single step of a Scene is as follows:\n\n1. [PRE_UPDATE]{@linkcode Phaser.Scenes.Events#event:PRE_UPDATE}\n2. [UPDATE]{@linkcode Phaser.Scenes.Events#event:UPDATE}\n3. The `Scene.update` method is called, if it exists\n4. [POST_UPDATE]{@linkcode Phaser.Scenes.Events#event:POST_UPDATE}\n5. [PRE_RENDER]{@linkcode Phaser.Scenes.Events#event:PRE_RENDER}\n6. [RENDER]{@linkcode Phaser.Scenes.Events#event:RENDER}\n\nListen to it from a Scene using `this.events.on('render', listener)`.\n\nA Scene will only render if it is visible.\n\nBy the time this event is dispatched, the Scene will have already been rendered.", + "Phaser.Scenes.Events.RESUME": "The Scene Systems Resume Event.\n\nThis event is dispatched by a Scene when it is resumed from a paused state, either directly via the `resume` method,\nor as an action from another Scene.\n\nListen to it from a Scene using `this.events.on('resume', listener)`.", + "Phaser.Scenes.Events.SHUTDOWN": "The Scene Systems Shutdown Event.\n\nThis event is dispatched by a Scene during the Scene Systems shutdown process.\n\nListen to it from a Scene using `this.events.on('shutdown', listener)`.\n\nYou should free-up any resources that may be in use by your Scene in this event handler, on the understanding\nthat the Scene may, at any time, become active again. A shutdown Scene is not 'destroyed', it's simply not\ncurrently active. Use the [DESTROY]{@linkcode Phaser.Scenes.Events#event:DESTROY} event to completely clear resources.", + "Phaser.Scenes.Events.SLEEP": "The Scene Systems Sleep Event.\n\nThis event is dispatched by a Scene when it is sent to sleep, either directly via the `sleep` method,\nor as an action from another Scene.\n\nListen to it from a Scene using `this.events.on('sleep', listener)`.", + "Phaser.Scenes.Events.START": "The Scene Systems Start Event.\n\nThis event is dispatched by a Scene during the Scene Systems start process. Primarily used by Scene Plugins.\n\nListen to it from a Scene using `this.events.on('start', listener)`.", + "Phaser.Scenes.Events.TRANSITION_COMPLETE": "The Scene Transition Complete Event.\n\nThis event is dispatched by the Target Scene of a transition.\n\nIt happens when the transition process has completed. This occurs when the duration timer equals or exceeds the duration\nof the transition.\n\nListen to it from a Scene using `this.events.on('transitioncomplete', listener)`.\n\nThe Scene Transition event flow is as follows:\n\n1. [TRANSITION_OUT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_OUT} - the Scene that started the transition will emit this event.\n2. [TRANSITION_INIT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_INIT} - the Target Scene will emit this event if it has an `init` method.\n3. [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} - the Target Scene will emit this event after its `create` method is called, OR ...\n4. [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} - the Target Scene will emit this event if it was asleep and has been woken-up to be transitioned to.\n5. [TRANSITION_COMPLETE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_COMPLETE} - the Target Scene will emit this event when the transition finishes.", + "Phaser.Scenes.Events.TRANSITION_INIT": "The Scene Transition Init Event.\n\nThis event is dispatched by the Target Scene of a transition.\n\nIt happens immediately after the `Scene.init` method is called. If the Scene does not have an `init` method,\nthis event is not dispatched.\n\nListen to it from a Scene using `this.events.on('transitioninit', listener)`.\n\nThe Scene Transition event flow is as follows:\n\n1. [TRANSITION_OUT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_OUT} - the Scene that started the transition will emit this event.\n2. [TRANSITION_INIT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_INIT} - the Target Scene will emit this event if it has an `init` method.\n3. [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} - the Target Scene will emit this event after its `create` method is called, OR ...\n4. [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} - the Target Scene will emit this event if it was asleep and has been woken-up to be transitioned to.\n5. [TRANSITION_COMPLETE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_COMPLETE} - the Target Scene will emit this event when the transition finishes.", + "Phaser.Scenes.Events.TRANSITION_OUT": "The Scene Transition Out Event.\n\nThis event is dispatched by a Scene when it initiates a transition to another Scene.\n\nListen to it from a Scene using `this.events.on('transitionout', listener)`.\n\nThe Scene Transition event flow is as follows:\n\n1. [TRANSITION_OUT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_OUT} - the Scene that started the transition will emit this event.\n2. [TRANSITION_INIT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_INIT} - the Target Scene will emit this event if it has an `init` method.\n3. [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} - the Target Scene will emit this event after its `create` method is called, OR ...\n4. [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} - the Target Scene will emit this event if it was asleep and has been woken-up to be transitioned to.\n5. [TRANSITION_COMPLETE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_COMPLETE} - the Target Scene will emit this event when the transition finishes.", + "Phaser.Scenes.Events.TRANSITION_START": "The Scene Transition Start Event.\n\nThis event is dispatched by the Target Scene of a transition, only if that Scene was not asleep.\n\nIt happens immediately after the `Scene.create` method is called. If the Scene does not have a `create` method,\nthis event is dispatched anyway.\n\nIf the Target Scene was sleeping then the [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} event is\ndispatched instead of this event.\n\nListen to it from a Scene using `this.events.on('transitionstart', listener)`.\n\nThe Scene Transition event flow is as follows:\n\n1. [TRANSITION_OUT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_OUT} - the Scene that started the transition will emit this event.\n2. [TRANSITION_INIT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_INIT} - the Target Scene will emit this event if it has an `init` method.\n3. [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} - the Target Scene will emit this event after its `create` method is called, OR ...\n4. [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} - the Target Scene will emit this event if it was asleep and has been woken-up to be transitioned to.\n5. [TRANSITION_COMPLETE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_COMPLETE} - the Target Scene will emit this event when the transition finishes.", + "Phaser.Scenes.Events.TRANSITION_WAKE": "The Scene Transition Wake Event.\n\nThis event is dispatched by the Target Scene of a transition, only if that Scene was asleep before\nthe transition began. If the Scene was not asleep the [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} event is dispatched instead.\n\nListen to it from a Scene using `this.events.on('transitionwake', listener)`.\n\nThe Scene Transition event flow is as follows:\n\n1. [TRANSITION_OUT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_OUT} - the Scene that started the transition will emit this event.\n2. [TRANSITION_INIT]{@linkcode Phaser.Scenes.Events#event:TRANSITION_INIT} - the Target Scene will emit this event if it has an `init` method.\n3. [TRANSITION_START]{@linkcode Phaser.Scenes.Events#event:TRANSITION_START} - the Target Scene will emit this event after its `create` method is called, OR ...\n4. [TRANSITION_WAKE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_WAKE} - the Target Scene will emit this event if it was asleep and has been woken-up to be transitioned to.\n5. [TRANSITION_COMPLETE]{@linkcode Phaser.Scenes.Events#event:TRANSITION_COMPLETE} - the Target Scene will emit this event when the transition finishes.", + "Phaser.Scenes.Events.UPDATE": "The Scene Systems Update Event.\n\nThis event is dispatched by a Scene during the main game loop step.\n\nThe event flow for a single step of a Scene is as follows:\n\n1. [PRE_UPDATE]{@linkcode Phaser.Scenes.Events#event:PRE_UPDATE}\n2. [UPDATE]{@linkcode Phaser.Scenes.Events#event:UPDATE}\n3. The `Scene.update` method is called, if it exists and the Scene is in a Running state, otherwise this is skipped.\n4. [POST_UPDATE]{@linkcode Phaser.Scenes.Events#event:POST_UPDATE}\n5. [PRE_RENDER]{@linkcode Phaser.Scenes.Events#event:PRE_RENDER}\n6. [RENDER]{@linkcode Phaser.Scenes.Events#event:RENDER}\n\nListen to it from a Scene using `this.events.on('update', listener)`.\n\nA Scene will only run its step if it is active.", + "Phaser.Scenes.Events.WAKE": "The Scene Systems Wake Event.\n\nThis event is dispatched by a Scene when it is woken from sleep, either directly via the `wake` method,\nor as an action from another Scene.\n\nListen to it from a Scene using `this.events.on('wake', listener)`.", + "Phaser.Sound.Events.COMPLETE": "The Sound Complete Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they complete playback.\n\nListen to it from a Sound instance using `Sound.on('complete', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('complete', listener);\nmusic.play();\n```", + "Phaser.Sound.Events.DECODED_ALL": "The Audio Data Decoded All Event.\n\nThis event is dispatched by the Web Audio Sound Manager as a result of calling the `decodeAudio` method,\nonce all files passed to the method have been decoded (or errored).\n\nUse `Phaser.Sound.Events#DECODED` to listen for single sounds being decoded, and `DECODED_ALL` to\nlisten for them all completing.\n\nListen to it from the Sound Manager in a Scene using `this.sound.on('decodedall', listener)`, i.e.:\n\n```javascript\nthis.sound.once('decodedall', handler);\nthis.sound.decodeAudio([ audioFiles ]);\n```", + "Phaser.Sound.Events.DECODED": "The Audio Data Decoded Event.\n\nThis event is dispatched by the Web Audio Sound Manager as a result of calling the `decodeAudio` method.\n\nListen to it from the Sound Manager in a Scene using `this.sound.on('decoded', listener)`, i.e.:\n\n```javascript\nthis.sound.on('decoded', handler);\nthis.sound.decodeAudio(key, audioData);\n```", + "Phaser.Sound.Events.DESTROY": "The Sound Destroy Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are destroyed, either\ndirectly or via a Sound Manager.\n\nListen to it from a Sound instance using `Sound.on('destroy', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('destroy', listener);\nmusic.destroy();\n```", + "Phaser.Sound.Events.DETUNE": "The Sound Detune Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their detune value changes.\n\nListen to it from a Sound instance using `Sound.on('detune', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('detune', listener);\nmusic.play();\nmusic.setDetune(200);\n```", + "Phaser.Sound.Events.GLOBAL_DETUNE": "The Sound Manager Global Detune Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched when the `detune` property of the Sound Manager is changed, which globally\nadjusts the detuning of all active sounds.\n\nListen to it from a Scene using: `this.sound.on('rate', listener)`.", + "Phaser.Sound.Events.GLOBAL_MUTE": "The Sound Manager Global Mute Event.\n\nThis event is dispatched by the Sound Manager when its `mute` property is changed, either directly\nor via the `setMute` method. This changes the mute state of all active sounds.\n\nListen to it from a Scene using: `this.sound.on('mute', listener)`.", + "Phaser.Sound.Events.GLOBAL_RATE": "The Sound Manager Global Rate Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched when the `rate` property of the Sound Manager is changed, which globally\nadjusts the playback rate of all active sounds.\n\nListen to it from a Scene using: `this.sound.on('rate', listener)`.", + "Phaser.Sound.Events.GLOBAL_VOLUME": "The Sound Manager Global Volume Event.\n\nThis event is dispatched by the Sound Manager when its `volume` property is changed, either directly\nor via the `setVolume` method. This changes the volume of all active sounds.\n\nListen to it from a Scene using: `this.sound.on('volume', listener)`.", + "Phaser.Sound.Events.LOOPED": "The Sound Looped Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they loop during playback.\n\nListen to it from a Sound instance using `Sound.on('looped', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('looped', listener);\nmusic.setLoop(true);\nmusic.play();\n```\n\nThis is not to be confused with the [LOOP]{@linkcode Phaser.Sound.Events#event:LOOP} event, which only emits when the loop state of a Sound is changed.", + "Phaser.Sound.Events.LOOP": "The Sound Loop Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their loop state is changed.\n\nListen to it from a Sound instance using `Sound.on('loop', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('loop', listener);\nmusic.setLoop(true);\n```\n\nThis is not to be confused with the [LOOPED]{@linkcode Phaser.Sound.Events#event:LOOPED} event, which emits each time a Sound loops during playback.", + "Phaser.Sound.Events.MUTE": "The Sound Mute Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their mute state changes.\n\nListen to it from a Sound instance using `Sound.on('mute', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('mute', listener);\nmusic.play();\nmusic.setMute(true);\n```", + "Phaser.Sound.Events.PAN": "The Sound Pan Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their pan changes.\n\nListen to it from a Sound instance using `Sound.on('pan', listener)`, i.e.:\n\n```javascript\nvar sound = this.sound.add('key');\nsound.on('pan', listener);\nsound.play();\nsound.setPan(0.5);\n```", + "Phaser.Sound.Events.PAUSE_ALL": "The Pause All Sounds Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched when the `pauseAll` method is invoked and after all current Sounds\nhave been paused.\n\nListen to it from a Scene using: `this.sound.on('pauseall', listener)`.", + "Phaser.Sound.Events.PAUSE": "The Sound Pause Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are paused.\n\nListen to it from a Sound instance using `Sound.on('pause', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('pause', listener);\nmusic.play();\nmusic.pause();\n```", + "Phaser.Sound.Events.PLAY": "The Sound Play Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are played.\n\nListen to it from a Sound instance using `Sound.on('play', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('play', listener);\nmusic.play();\n```", + "Phaser.Sound.Events.RATE": "The Sound Rate Change Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their rate changes.\n\nListen to it from a Sound instance using `Sound.on('rate', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('rate', listener);\nmusic.play();\nmusic.setRate(0.5);\n```", + "Phaser.Sound.Events.RESUME_ALL": "The Resume All Sounds Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched when the `resumeAll` method is invoked and after all current Sounds\nhave been resumed.\n\nListen to it from a Scene using: `this.sound.on('resumeall', listener)`.", + "Phaser.Sound.Events.RESUME": "The Sound Resume Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are resumed from a paused state.\n\nListen to it from a Sound instance using `Sound.on('resume', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('resume', listener);\nmusic.play();\nmusic.pause();\nmusic.resume();\n```", + "Phaser.Sound.Events.SEEK": "The Sound Seek Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are seeked to a new position.\n\nListen to it from a Sound instance using `Sound.on('seek', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('seek', listener);\nmusic.play();\nmusic.setSeek(5000);\n```", + "Phaser.Sound.Events.STOP_ALL": "The Stop All Sounds Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched when the `stopAll` method is invoked and after all current Sounds\nhave been stopped.\n\nListen to it from a Scene using: `this.sound.on('stopall', listener)`.", + "Phaser.Sound.Events.STOP": "The Sound Stop Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when they are stopped.\n\nListen to it from a Sound instance using `Sound.on('stop', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('stop', listener);\nmusic.play();\nmusic.stop();\n```", + "Phaser.Sound.Events.UNLOCKED": "The Sound Manager Unlocked Event.\n\nThis event is dispatched by the Base Sound Manager, or more typically, an instance of the Web Audio Sound Manager,\nor the HTML5 Audio Manager. It is dispatched during the update loop when the Sound Manager becomes unlocked. For\nWeb Audio this is on the first user gesture on the page.\n\nListen to it from a Scene using: `this.sound.on('unlocked', listener)`.", + "Phaser.Sound.Events.VOLUME": "The Sound Volume Event.\n\nThis event is dispatched by both Web Audio and HTML5 Audio Sound objects when their volume changes.\n\nListen to it from a Sound instance using `Sound.on('volume', listener)`, i.e.:\n\n```javascript\nvar music = this.sound.add('key');\nmusic.on('volume', listener);\nmusic.play();\nmusic.setVolume(0.5);\n```", + "Phaser.Structs.Events.PROCESS_QUEUE_ADD": "The Process Queue Add Event.\n\nThis event is dispatched by a Process Queue when a new item is successfully moved to its active list.\n\nYou will most commonly see this used by a Scene's Update List when a new Game Object has been added.\n\nIn that instance, listen to this event from within a Scene using: `this.sys.updateList.on('add', listener)`.", + "Phaser.Structs.Events.PROCESS_QUEUE_REMOVE": "The Process Queue Remove Event.\n\nThis event is dispatched by a Process Queue when a new item is successfully removed from its active list.\n\nYou will most commonly see this used by a Scene's Update List when a Game Object has been removed.\n\nIn that instance, listen to this event from within a Scene using: `this.sys.updateList.on('remove', listener)`.", + "Phaser.Textures.Events.ADD": "The Texture Add Event.\n\nThis event is dispatched by the Texture Manager when a texture is added to it.\n\nListen to this event from within a Scene using: `this.textures.on('addtexture', listener)`.", + "Phaser.Textures.Events.ADD_KEY": "The Texture Add Key Event.\n\nThis event is dispatched by the Texture Manager when a texture with the given key is added to it.\n\nListen to this event from within a Scene using: `this.textures.on('addtexture-key', listener)`.", + "Phaser.Textures.Events.ERROR": "The Texture Load Error Event.\n\nThis event is dispatched by the Texture Manager when a texture it requested to load failed.\nThis only happens when base64 encoded textures fail. All other texture types are loaded via the Loader Plugin.\n\nListen to this event from within a Scene using: `this.textures.on('onerror', listener)`.", + "Phaser.Textures.Events.LOAD": "The Texture Load Event.\n\nThis event is dispatched by the Texture Manager when a texture has finished loading on it.\nThis only happens for base64 encoded textures. All other texture types are loaded via the Loader Plugin.\n\nListen to this event from within a Scene using: `this.textures.on('onload', listener)`.\n\nThis event is dispatched after the [ADD]{@linkcode Phaser.Textures.Events#event:ADD} event.", + "Phaser.Textures.Events.READY": "This internal event signifies that the Texture Manager is now ready and the Game can continue booting.\n\nWhen a Phaser Game instance is booting for the first time, the Texture Manager has to wait on a couple of non-blocking\nasync events before it's fully ready to carry on. When those complete the Texture Manager emits this event via the Game\ninstance, which tells the Game to carry on booting.", + "Phaser.Textures.Events.REMOVE": "The Texture Remove Event.\n\nThis event is dispatched by the Texture Manager when a texture is removed from it.\n\nListen to this event from within a Scene using: `this.textures.on('removetexture', listener)`.\n\nIf you have any Game Objects still using the removed texture, they will start throwing\nerrors the next time they try to render. Be sure to clear all use of the texture in this event handler.", + "Phaser.Textures.Events.REMOVE_KEY": "The Texture Remove Key Event.\n\nThis event is dispatched by the Texture Manager when a texture with the given key is removed from it.\n\nListen to this event from within a Scene using: `this.textures.on('removetexture-key', listener)`.\n\nIf you have any Game Objects still using the removed texture, they will start throwing\nerrors the next time they try to render. Be sure to clear all use of the texture in this event handler.", + "Phaser.Tweens.Events.TWEEN_ACTIVE": "The Tween Active Event.\n\nThis event is dispatched by a Tween when it becomes active within the Tween Manager.\n\nAn 'active' Tween is one that is now progressing, although it may not yet be updating\nany target properties, due to settings such as `delay`. If you need an event for when\nthe Tween starts actually updating its first property, see `TWEEN_START`.\n\nListen to it from a Tween instance using `Tween.on('active', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.create({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000\n});\ntween.on('active', listener);\nthis.tweens.existing(tween);\n```\n\nNote that this event is usually dispatched already by the time you call `this.tweens.add()`, and is\nmeant for use with `tweens.create()` and/or `tweens.existing()`.", + "Phaser.Tweens.Events.TWEEN_COMPLETE": "The Tween Complete Event.\n\nThis event is dispatched by a Tween when it completes playback entirely, factoring in repeats and loops.\n\nIf the Tween has been set to loop or repeat infinitely, this event will not be dispatched\nunless the `Tween.stop` method is called.\n\nIf a Tween has a `completeDelay` set, this event will fire after that delay expires.\n\nListen to it from a Tween instance using `Tween.on('complete', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000\n});\ntween.on('complete', listener);\n```", + "Phaser.Tweens.Events.TWEEN_LOOP": "The Tween Loop Event.\n\nThis event is dispatched by a Tween when it loops.\n\nThis event will only be dispatched if the Tween has a loop count set.\n\nIf a Tween has a `loopDelay` set, this event will fire after that delay expires.\n\nThe difference between `loop` and `repeat` is that `repeat` is a property setting,\nwhere-as `loop` applies to the entire Tween.\n\nListen to it from a Tween instance using `Tween.on('loop', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000,\n loop: 6\n});\ntween.on('loop', listener);\n```", + "Phaser.Tweens.Events.TWEEN_PAUSE": "The Tween Pause Event.\n\nThis event is dispatched by a Tween when it is paused.\n\nListen to it from a Tween instance using `Tween.on('pause', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n ease: 'Power1',\n duration: 3000,\n x: 600\n});\ntween.on('pause', listener);\n// At some point later ...\ntween.pause();\n```", + "Phaser.Tweens.Events.TWEEN_REPEAT": "The Tween Repeat Event.\n\nThis event is dispatched by a Tween when one of the properties it is tweening repeats.\n\nThis event will only be dispatched if the Tween has a property with a repeat count set.\n\nIf a Tween has a `repeatDelay` set, this event will fire after that delay expires.\n\nThe difference between `loop` and `repeat` is that `repeat` is a property setting,\nwhere-as `loop` applies to the entire Tween.\n\nListen to it from a Tween instance using `Tween.on('repeat', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000,\n repeat: 4\n});\ntween.on('repeat', listener);\n```", + "Phaser.Tweens.Events.TWEEN_RESUME": "The Tween Resume Event.\n\nThis event is dispatched by a Tween when it is resumed from a paused state.\n\nListen to it from a Tween instance using `Tween.on('resume', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n ease: 'Power1',\n duration: 3000,\n x: 600\n});\ntween.on('resume', listener);\n// At some point later ...\ntween.resume();\n```", + "Phaser.Tweens.Events.TWEEN_START": "The Tween Start Event.\n\nThis event is dispatched by a Tween when it starts tweening its first property.\n\nA Tween will only emit this event once, as it can only start once.\n\nIf a Tween has a `delay` set, this event will fire after that delay expires.\n\nListen to it from a Tween instance using `Tween.on('start', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000\n});\ntween.on('start', listener);\n```", + "Phaser.Tweens.Events.TWEEN_STOP": "The Tween Stop Event.\n\nThis event is dispatched by a Tween when it is stopped.\n\nListen to it from a Tween instance using `Tween.on('stop', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000\n});\ntween.on('stop', listener);\n```", + "Phaser.Tweens.Events.TWEEN_UPDATE": "The Tween Update Event.\n\nThis event is dispatched by a Tween every time it updates _any_ of the properties it is tweening.\n\nA Tween that is changing 3 properties of a target will emit this event 3 times per change, once per property.\n\n**Note:** This is a very high frequency event and may be dispatched multiple times, every single frame.\n\nListen to it from a Tween instance using `Tween.on('update', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000,\n});\ntween.on('update', listener);\n```", + "Phaser.Tweens.Events.TWEEN_YOYO": "The Tween Yoyo Event.\n\nThis event is dispatched by a Tween whenever a property it is tweening yoyos.\n\nThis event will only be dispatched if the Tween has a property with `yoyo` set.\n\nIf the Tween has a `hold` value, this event is dispatched when the hold expires.\n\nThis event is dispatched for every property, and for every target, that yoyos.\nFor example, if a Tween was updating 2 properties and had 10 targets, this event\nwould be dispatched 20 times (twice per target). So be careful how you use it!\n\nListen to it from a Tween instance using `Tween.on('yoyo', listener)`, i.e.:\n\n```javascript\nvar tween = this.tweens.add({\n targets: image,\n x: 500,\n ease: 'Power1',\n duration: 3000,\n yoyo: true\n});\ntween.on('yoyo', listener);\n```" +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/plugin.json b/source/editor/plugins/phasereditor2d.scene/plugin.json index 2787e9f33..eb22703ff 100644 --- a/source/editor/plugins/phasereditor2d.scene/plugin.json +++ b/source/editor/plugins/phasereditor2d.scene/plugin.json @@ -1,7 +1,8 @@ { "id": "phasereditor2d.scene", "styles": [ - "styles/SceneEditor.css" + "styles/SceneEditor.css", + "styles/EventPropertyDialog.css" ], "scripts": [ "libs/localforage.js", diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index a70770ad2..052f06543 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -87,6 +87,7 @@ namespace phasereditor2d.scene { private _sceneFinder: core.json.SceneFinder; private _docs: phasereditor2d.ide.core.PhaserDocs; + private _eventsDocs: phasereditor2d.ide.core.PhaserDocs; static getInstance() { return this._instance; @@ -95,7 +96,12 @@ namespace phasereditor2d.scene { private constructor() { super("phasereditor2d.scene"); - this._docs = new phasereditor2d.ide.core.PhaserDocs(this, "data/phaser-docs.json"); + this._docs = new phasereditor2d.ide.core.PhaserDocs( + this, + "data/phaser-docs.json", + "data/events-docs.json"); + + this._eventsDocs = new phasereditor2d.ide.core.PhaserDocs(this, "data/events-docs.json"); } async starting() { @@ -130,9 +136,15 @@ namespace phasereditor2d.scene { } getPhaserDocs() { + return this._docs; } + getPhaserEventsDocs() { + + return this._eventsDocs; + } + registerExtensions(reg: colibri.ExtensionRegistry) { this._sceneFinder = new core.json.SceneFinder(); @@ -150,6 +162,11 @@ namespace phasereditor2d.scene { await ScenePlugin.getInstance().getPhaserDocs().preload(); })); + reg.addExtension(new ide.PluginResourceLoaderExtension(async () => { + + await ScenePlugin.getInstance().getPhaserEventsDocs().preload(); + })); + // preload UserComponent files reg.addExtension(new ide.PluginResourceLoaderExtension(async () => { @@ -482,6 +499,7 @@ namespace phasereditor2d.scene { new ui.sceneobjects.OptionPropertyType(), new ui.sceneobjects.ObjectVarPropertyType(), new ui.sceneobjects.ObjectConstructorPropertyType(), + new ui.sceneobjects.EventPropertyType(), new ui.sceneobjects.TextureConfigPropertyType(), new ui.sceneobjects.AnimationKeyPropertyType(), new ui.sceneobjects.AudioKeyPropertyType(), diff --git a/source/editor/plugins/phasereditor2d.scene/src/core/code/SceneCodeDOMBuilder.ts b/source/editor/plugins/phasereditor2d.scene/src/core/code/SceneCodeDOMBuilder.ts index e24e970e7..b3afd7b91 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/core/code/SceneCodeDOMBuilder.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/core/code/SceneCodeDOMBuilder.ts @@ -983,7 +983,8 @@ namespace phasereditor2d.scene.core.code { objectVarName: varname, prefabSerializer: prefabSerializer, unit: this._unit, - sceneFile: this._sceneFile + sceneFile: this._sceneFile, + obj }); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts index 79fcefa75..6c6aeb729 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/Component.ts @@ -11,7 +11,8 @@ namespace phasereditor2d.scene.ui.sceneobjects { objectVarName: string; prefabSerializer: core.json.Serializer; unit: core.code.UnitCodeDOM; - sceneFile: io.FilePath + sceneFile: io.FilePath, + obj: ISceneGameObject } export interface IBuildPrefabExtraTypeScriptDefinitionsCodeDOMArgs { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts index be98a9949..b1afaae42 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts @@ -136,7 +136,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { viewer.setInput([]); - const dlg = new controls.dialogs.ViewerDialog(viewer, true); + const dlg = this.createDialogInstance(viewer, true); const size = this.getDialogSize(); @@ -163,6 +163,12 @@ namespace phasereditor2d.scene.ui.sceneobjects { controls.viewers.GridTreeViewerRenderer.expandSections(viewer); } + protected createDialogInstance(viewer: controls.viewers.TreeViewer, showZoomControls: boolean) + : controls.dialogs.AbstractViewerDialog { + + return new controls.dialogs.ViewerDialog(viewer, showZoomControls) + } + protected abstract valueToString(viewer: controls.viewers.TreeViewer, value: any): string; protected abstract loadViewerInput(viewer: controls.viewers.TreeViewer): void; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts new file mode 100644 index 000000000..b4a063c5f --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts @@ -0,0 +1,151 @@ +/// + +namespace phasereditor2d.scene.ui.sceneobjects { + + import controls = colibri.ui.controls; + + export class EventPropertyType extends AbstractDialogPropertyType { + + constructor() { + super({ + id: "event", + dialogTitle: "Select Event", + name: "Event Dialog", + hasCustomIcon: false + }); + } + + getName() { + + return "Event"; + } + + renderValue(value: any): string { + + return value; + } + + private isPhaserBuiltIn(value: string) { + + return value.startsWith("Phaser."); + } + + private getCodeValue(value: string) { + + if (this.isPhaserBuiltIn(value)) { + + return value; + } + + return `"${value}"`; + } + + protected createDialogInstance(viewer: controls.viewers.TreeViewer, zoom: boolean) { + + return new EventPropertyDialog(viewer); + } + + buildDeclarePropertyCodeDOM(prop: UserProperty, value: string): core.code.FieldDeclCodeDOM { + + const codeValue = this.getCodeValue(value); + + return this.buildExpressionFieldCode(prop, "string", codeValue); + } + + buildSetObjectPropertyCodeDOM(comp: Component, args: ISetObjectPropertiesCodeDOMArgs, userProp: UserProperty): void { + + const prop = userProp.getComponentProperty(); + const value = prop.getValue(args.obj); + + if (this.isPhaserBuiltIn(value)) { + + comp.buildSetObjectPropertyCodeDOM_StringVerbatimProperty(args, prop); + + } else { + + comp.buildSetObjectPropertyCodeDOM_StringProperty(args, prop); + } + } + + protected async createViewer() { + + const viewer = new controls.viewers.TreeViewer("phasereditor2d.scene.editor.EventPropertyType.Dialog"); + viewer.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider( + () => new controls.viewers.EmptyCellRenderer(false))); + viewer.setLabelProvider(new controls.viewers.LabelProvider()); + viewer.setStyledLabelProvider(new EventPropertyStyleLabelProider()); + viewer.setContentProvider(new controls.viewers.ArrayTreeContentProvider()); + + return viewer; + } + + protected valueToString(viewer: colibri.ui.controls.viewers.TreeViewer, value: string): string { + + return value; + } + + protected loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer): void { + + const docs = ScenePlugin.getInstance().getPhaserEventsDocs(); + const keys = docs.getKeys(); + + viewer.setInput(keys); + } + } + + class EventPropertyDialog extends controls.dialogs.ViewerFormDialog { + + constructor(viewer: controls.viewers.TreeViewer) { + super(viewer, false); + + this.setSize(undefined, 600, true); + } + + protected createFormArea(formArea: HTMLDivElement): void { + + const docsArea = document.createElement("div"); + docsArea.innerHTML = ""; + + formArea.appendChild(docsArea); + formArea.classList.add("EventPropertyDialogHelpPane"); + + const viewer = this.getViewer(); + + viewer.eventSelectionChanged.addListener(sel => { + + const [event] = sel as string[]; + + if (event) { + + const doc = ScenePlugin.getInstance().getPhaserEventsDocs().getDoc(event, false) || ""; + + docsArea.innerHTML = doc; + } + }); + } + } + + class EventPropertyStyleLabelProider implements controls.viewers.IStyledLabelProvider { + + getStyledTexts(obj: any, dark: boolean): controls.viewers.IStyledText[] { + + const label = obj as string; + const i = label.lastIndexOf("."); + const namespace_ = label.substring(0, i + 1); + const name = label.substring(i + 1); + + const theme = controls.Controls.getTheme(); + + return [ + { + color: theme.viewerForeground + "90", + text: namespace_ + }, + { + color: theme.viewerForeground, + text: name + } + ]; + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css b/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css new file mode 100644 index 000000000..5cf73f297 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css @@ -0,0 +1,10 @@ +.EventPropertyDialogHelpPane { + height: 10rem; + overflow-y: scroll; +} + +.dark .EventPropertyDialogHelpPane { + border-top-style: solid; + border-top-width: 1px; + border-radius: 0px; +} \ No newline at end of file From db08cf54b5fed8ee72041e8e33dd44bc5ac44a9a Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 14 Jun 2023 02:30:13 -0400 Subject: [PATCH 33/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index daee53d86..7384e4133 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -2,6 +2,7 @@ ## v3.61.1-dev +* New Event user property. * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. * A new Add Prefab Property command that shows a dialog. * Replaces the Object Depth commands for the Edit move commands. From 0349f16d69060244d78ecae08a2f4ee8d1c43be7 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 14 Jun 2023 03:30:00 -0400 Subject: [PATCH 34/72] Allows defining user events for the User property. --- .../phasereditor2d.ide/src/core/PhaserDocs.ts | 7 +++ .../src/core/json/SceneFinder.ts | 47 ++++++++++++++++++- .../AbstractDialogPropertyType.ts | 4 +- .../userProperties/EventPropertyType.ts | 42 ++++++++++++++--- .../userProperties/ObjectVarPropertyType.ts | 2 +- .../styles/EventPropertyDialog.css | 1 + 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts b/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts index 5ce28fe2d..e8f16bdae 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/core/PhaserDocs.ts @@ -12,6 +12,13 @@ namespace phasereditor2d.ide.core { this._files = files; } + static markdownToHtml(txt: string) { + + const converter = new showdown.Converter(); + + return converter.makeHtml(txt); + } + async preload() { if (!this._data) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts index b5ba65213..d239b7849 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts @@ -38,6 +38,12 @@ namespace phasereditor2d.scene.core.json { component: usercomponent.UserComponent } + export interface IUserEvent { + name: string; + help: string; + file: io.FilePath; + } + export class SceneFinder { private _prefabObjectId_ObjectData_Map: Map; @@ -245,7 +251,7 @@ namespace phasereditor2d.scene.core.json { sceneFiles.push(file); } catch (e) { - + console.error(`SceneDataTable: parsing file ${file.getFullName()}. Error: ${(e as Error).message}`); } @@ -538,5 +544,44 @@ namespace phasereditor2d.scene.core.json { console.log(this._prefabObjectId_ObjectData_Map.get(id)); } } + + async findUserEvents(): Promise { + + const result: IUserEvent[] = []; + + for (const file of colibri.ui.ide.FileUtils.getAllFiles()) { + + if (file.getName() === "events.txt") { + + const content = await colibri.ui.ide.FileUtils.preloadAndGetFileString(file); + const lines = content.split("\n"); + + for (let line of lines) { + + line = line.trim(); + + if (line.length === 0) { + + continue; + } + + let name = line; + let help = ""; + + const i = line.indexOf(" "); + + if (i > 0) { + + name = line.substring(0, i); + help = line.substring(i + 1); + } + + result.push({ name, help, file }); + } + } + } + + return result; + } } } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts index b1afaae42..3a2aab0b5 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts @@ -156,7 +156,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { dlg.addCancelButton(); - this.loadViewerInput(viewer); + await this.loadViewerInput(viewer); this.revealValue(viewer, revealValue); @@ -171,7 +171,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { protected abstract valueToString(viewer: controls.viewers.TreeViewer, value: any): string; - protected abstract loadViewerInput(viewer: controls.viewers.TreeViewer): void; + protected abstract loadViewerInput(viewer: controls.viewers.TreeViewer): Promise; protected revealValue(viewer: controls.viewers.TreeViewer, value: string) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts index b4a063c5f..e8eec7067 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts @@ -84,12 +84,19 @@ namespace phasereditor2d.scene.ui.sceneobjects { return value; } - protected loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer): void { + protected async loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer) { const docs = ScenePlugin.getInstance().getPhaserEventsDocs(); - const keys = docs.getKeys(); - viewer.setInput(keys); + const phaserNames = docs.getKeys(); + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const events = await finder.findUserEvents(); + + const userNames = events.map(e => e.name); + + viewer.setInput([...userNames, ...phaserNames]); } } @@ -111,15 +118,36 @@ namespace phasereditor2d.scene.ui.sceneobjects { const viewer = this.getViewer(); + const userEvents: core.json.IUserEvent[] = []; + + ScenePlugin.getInstance().getSceneFinder().findUserEvents().then(events => { + + userEvents.push(...events); + }) + viewer.eventSelectionChanged.addListener(sel => { - const [event] = sel as string[]; + const [eventName] = sel as string[]; + + if (eventName) { + + let help = ""; + + if (eventName.startsWith("Phaser.")) { + + help = ScenePlugin.getInstance().getPhaserEventsDocs().getDoc(eventName, false) || ""; + + } else { + + const event = userEvents.find(e => e.name === eventName); - if (event) { + if (event) { - const doc = ScenePlugin.getInstance().getPhaserEventsDocs().getDoc(event, false) || ""; + help = phasereditor2d.ide.core.PhaserDocs.markdownToHtml(event.help) + } + } - docsArea.innerHTML = doc; + docsArea.innerHTML = help; } }); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts index e69a2ed81..8097ac048 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/ObjectVarPropertyType.ts @@ -70,7 +70,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { return core.code.formatToValidVarName(viewer.getLabelProvider().getLabel(value)); } - protected loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer): void { + protected async loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer): Promise { const scene = this.getEditor().getScene(); diff --git a/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css b/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css index 5cf73f297..ff469ba58 100644 --- a/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css +++ b/source/editor/plugins/phasereditor2d.scene/styles/EventPropertyDialog.css @@ -1,6 +1,7 @@ .EventPropertyDialogHelpPane { height: 10rem; overflow-y: scroll; + align-items: start !important; } .dark .EventPropertyDialogHelpPane { From 6bf1bf1a4bcfb1117882d47e44835eebf80cb3bb Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 14 Jun 2023 13:52:22 -0400 Subject: [PATCH 35/72] Includes dynamic events: animationcomplete-key, keydown-key, keyup-key. --- .../userProperties/EventPropertyType.ts | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts index e8eec7067..83c8ac0c0 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/EventPropertyType.ts @@ -86,6 +86,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { protected async loadViewerInput(viewer: colibri.ui.controls.viewers.TreeViewer) { + // Phaser events const docs = ScenePlugin.getInstance().getPhaserEventsDocs(); const phaserNames = docs.getKeys(); @@ -94,9 +95,39 @@ namespace phasereditor2d.scene.ui.sceneobjects { const events = await finder.findUserEvents(); + // user events + const userNames = events.map(e => e.name); - viewer.setInput([...userNames, ...phaserNames]); + // Phaser animation dynamic events + + const packFinder = new pack.core.PackFinder(); + + await packFinder.preload(); + + const animEvents = packFinder + .getAssets(i => i instanceof pack.core.AnimationsAssetPackItem) + .map(i => i as pack.core.AnimationsAssetPackItem) + .flatMap(i => i.getAnimations()) + .map(anim => anim.getKey()) + .map(k => `animationcomplete-${k}`); + + // Phaser keyboard dynamic events + + const keyboardEvents = []; + + for(const k of Object.keys(Phaser.Input.Keyboard.KeyCodes)) { + + keyboardEvents.push(`keydown-${k}`, `keyup-${k}`); + } + + console.log(keyboardEvents); + + viewer.setInput([ + ...userNames, + ...phaserNames, + ...keyboardEvents, + ...animEvents]); } } @@ -129,13 +160,28 @@ namespace phasereditor2d.scene.ui.sceneobjects { const [eventName] = sel as string[]; + const phaserDocs = ScenePlugin.getInstance().getPhaserDocs(); + const eventsDocs = ScenePlugin.getInstance().getPhaserEventsDocs(); + if (eventName) { let help = ""; if (eventName.startsWith("Phaser.")) { - help = ScenePlugin.getInstance().getPhaserEventsDocs().getDoc(eventName, false) || ""; + help = eventsDocs.getDoc(eventName, false) || ""; + + } else if (eventName.startsWith("animationcomplete-")) { + + help = eventsDocs.getDoc("Phaser.Animations.Events.ANIMATION_COMPLETE_KEY", false); + + } else if (eventName.startsWith("keydown-")) { + + help = eventsDocs.getDoc("Phaser.Input.Keyboard.Events.KEY_DOWN", false); + + } if (eventName.startsWith("keyup-")) { + + help = eventsDocs.getDoc("Phaser.Input.Keyboard.Events.KEY_UP", false); } else { From 28ec0922984cacafe0bdb131b1ceff35c56299b5 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 15 Jun 2023 14:10:44 -0400 Subject: [PATCH 36/72] Moves PropertySection to its own file. --- .../ui/controls/properties/PropertyPage.ts | 146 ----------------- .../properties/PropertySectionPane.ts | 148 ++++++++++++++++++ 2 files changed, 148 insertions(+), 146 deletions(-) create mode 100644 source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts index 830865ff4..2db86a953 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts @@ -1,151 +1,5 @@ namespace colibri.ui.controls.properties { - class PropertySectionPane extends Control { - - private _section: PropertySection; - private _titleArea: HTMLDivElement; - private _formArea: HTMLDivElement; - private _page: PropertyPage; - private _menuIcon: IconControl; - private _expandIconControl: IconControl; - - constructor(page: PropertyPage, section: PropertySection) { - super(); - - this._page = page; - - this._section = section; - - this.addClass("PropertySectionPane"); - } - - createSection() { - - if (!this._formArea) { - - this._titleArea = document.createElement("div"); - this._titleArea.classList.add("PropertyTitleArea"); - this._titleArea.addEventListener("click", () => this.toggleSection()); - - this._expandIconControl = new IconControl(colibri.ColibriPlugin.getInstance().getIcon(colibri.ICON_CONTROL_TREE_COLLAPSE)); - - this._expandIconControl.getCanvas().classList.add("expanded"); - - this._expandIconControl.getCanvas().addEventListener("click", e => { - - e.stopImmediatePropagation(); - - this.toggleSection() - }); - - this._titleArea.appendChild(this._expandIconControl.getCanvas()); - - const label = document.createElement("label"); - label.innerText = this._section.getTitle(); - this._titleArea.appendChild(label); - - this._menuIcon = new IconControl(ColibriPlugin.getInstance().getIcon(ICON_SMALL_MENU)); - this._menuIcon.getCanvas().classList.add("IconButton"); - this._menuIcon.getCanvas().style.visibility = this._section.hasMenu() ? "visible" : "hidden"; - this._menuIcon.getCanvas().addEventListener("click", e => { - - e.stopPropagation(); - e.stopImmediatePropagation(); - - if (this._section.hasMenu()) { - - const menu = new Menu(); - this._section.createMenu(menu); - menu.createWithEvent(e); - } - }); - this._titleArea.appendChild(this._menuIcon.getCanvas()); - - this._formArea = document.createElement("div"); - this._formArea.classList.add("PropertyFormArea"); - this._section.create(this._formArea); - - this.getElement().appendChild(this._titleArea); - this.getElement().appendChild(this._formArea); - - this.updateExpandIcon(); - - let collapsed = this.getCollapsedStateInStorage(); - - if (collapsed === undefined) { - - this.setCollapsedStateInStorage(this._section.isCollapsedByDefault()); - - collapsed = this.getCollapsedStateInStorage(); - } - - if (collapsed === "true") { - - this.toggleSection(); - } - } - } - - private getCollapsedStateInStorage() { - - return window.localStorage[this.getLocalStorageKey() + ".collapsed"]; - } - - private setCollapsedStateInStorage(collapsed: boolean) { - - return window.localStorage[this.getLocalStorageKey() + ".collapsed"] = collapsed ? "true" : "false"; - } - - private getLocalStorageKey() { - - return `colibri.ui.controls.properties.PropertySection[${this._section.getId()}]`; - } - - - isExpanded() { - return this._expandIconControl.getCanvas().classList.contains("expanded"); - } - - private toggleSection(): void { - - if (this.isExpanded()) { - - this._formArea.style.display = "none"; - this._expandIconControl.getCanvas().classList.remove("expanded"); - - } else { - - this._formArea.style.display = "grid"; - this._expandIconControl.getCanvas().classList.add("expanded"); - } - - this._page.updateExpandStatus(); - - this.getContainer().dispatchLayoutEvent(); - - this.updateExpandIcon(); - - this.setCollapsedStateInStorage(!this.isExpanded()); - } - - private updateExpandIcon() { - - const icon = this.isExpanded() ? colibri.ICON_CONTROL_SECTION_COLLAPSE : colibri.ICON_CONTROL_SECTION_EXPAND; - - const image = ColibriPlugin.getInstance().getIcon(icon); - - this._expandIconControl.setIcon(image); - } - - getSection() { - return this._section; - } - - getFormArea() { - return this._formArea; - } - } - export class PropertyPage extends Control { private _sectionProvider: PropertySectionProvider; private _sectionPanes: PropertySectionPane[]; diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts new file mode 100644 index 000000000..ade9677d7 --- /dev/null +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts @@ -0,0 +1,148 @@ +namespace colibri.ui.controls.properties { + + export class PropertySectionPane extends Control { + + private _section: PropertySection; + private _titleArea: HTMLDivElement; + private _formArea: HTMLDivElement; + private _page: PropertyPage; + private _menuIcon: IconControl; + private _expandIconControl: IconControl; + + constructor(page: PropertyPage, section: PropertySection) { + super(); + + this._page = page; + + this._section = section; + + this.addClass("PropertySectionPane"); + } + + createSection() { + + if (!this._formArea) { + + this._titleArea = document.createElement("div"); + this._titleArea.classList.add("PropertyTitleArea"); + this._titleArea.addEventListener("click", () => this.toggleSection()); + + this._expandIconControl = new IconControl(colibri.ColibriPlugin.getInstance().getIcon(colibri.ICON_CONTROL_TREE_COLLAPSE)); + + this._expandIconControl.getCanvas().classList.add("expanded"); + + this._expandIconControl.getCanvas().addEventListener("click", e => { + + e.stopImmediatePropagation(); + + this.toggleSection() + }); + + this._titleArea.appendChild(this._expandIconControl.getCanvas()); + + const label = document.createElement("label"); + label.innerText = this._section.getTitle(); + this._titleArea.appendChild(label); + + this._menuIcon = new IconControl(ColibriPlugin.getInstance().getIcon(ICON_SMALL_MENU)); + this._menuIcon.getCanvas().classList.add("IconButton"); + this._menuIcon.getCanvas().style.visibility = this._section.hasMenu() ? "visible" : "hidden"; + this._menuIcon.getCanvas().addEventListener("click", e => { + + e.stopPropagation(); + e.stopImmediatePropagation(); + + if (this._section.hasMenu()) { + + const menu = new Menu(); + this._section.createMenu(menu); + menu.createWithEvent(e); + } + }); + this._titleArea.appendChild(this._menuIcon.getCanvas()); + + this._formArea = document.createElement("div"); + this._formArea.classList.add("PropertyFormArea"); + this._section.create(this._formArea); + + this.getElement().appendChild(this._titleArea); + this.getElement().appendChild(this._formArea); + + this.updateExpandIcon(); + + let collapsed = this.getCollapsedStateInStorage(); + + if (collapsed === undefined) { + + this.setCollapsedStateInStorage(this._section.isCollapsedByDefault()); + + collapsed = this.getCollapsedStateInStorage(); + } + + if (collapsed === "true") { + + this.toggleSection(); + } + } + } + + private getCollapsedStateInStorage() { + + return window.localStorage[this.getLocalStorageKey() + ".collapsed"]; + } + + private setCollapsedStateInStorage(collapsed: boolean) { + + return window.localStorage[this.getLocalStorageKey() + ".collapsed"] = collapsed ? "true" : "false"; + } + + private getLocalStorageKey() { + + return `colibri.ui.controls.properties.PropertySection[${this._section.getId()}]`; + } + + + isExpanded() { + return this._expandIconControl.getCanvas().classList.contains("expanded"); + } + + private toggleSection(): void { + + if (this.isExpanded()) { + + this._formArea.style.display = "none"; + this._expandIconControl.getCanvas().classList.remove("expanded"); + + } else { + + this._formArea.style.display = "grid"; + this._expandIconControl.getCanvas().classList.add("expanded"); + } + + this._page.updateExpandStatus(); + + this.getContainer().dispatchLayoutEvent(); + + this.updateExpandIcon(); + + this.setCollapsedStateInStorage(!this.isExpanded()); + } + + private updateExpandIcon() { + + const icon = this.isExpanded() ? colibri.ICON_CONTROL_SECTION_COLLAPSE : colibri.ICON_CONTROL_SECTION_EXPAND; + + const image = ColibriPlugin.getInstance().getIcon(icon); + + this._expandIconControl.setIcon(image); + } + + getSection() { + return this._section; + } + + getFormArea() { + return this._formArea; + } + } +} \ No newline at end of file From 208e9eb7b07a2591a9118d52b130c2fad695c5a6 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 22:34:57 -0400 Subject: [PATCH 37/72] Shows user component sections in the right place. --- .../ui/controls/properties/PropertyPage.ts | 1 + .../phasereditor2d.scene/src/ScenePlugin.ts | 14 +- .../properties/DynamicComponentSection.ts | 307 ++++++++++++++++++ .../DynamicUserComponentSectionExtension.ts | 24 ++ .../properties/SceneEditorPopertyProvider.ts | 4 +- .../ui/sceneobjects/texture/TextureSection.ts | 2 +- 6 files changed, 347 insertions(+), 5 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts index 2db86a953..49c6b2a14 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts @@ -211,6 +211,7 @@ namespace colibri.ui.controls.properties { } getSectionProvider() { + return this._sectionProvider; } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index 052f06543..84cc1a43a 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -375,7 +375,15 @@ namespace phasereditor2d.scene { page => new ui.sceneobjects.NestedPrefabObjectVariableSection(page), page => new ui.sceneobjects.PrefabInstanceSection(page), page => new ui.sceneobjects.ObjectUserComponentsSection(page), - page => new ui.sceneobjects.ObjectSingleUserComponentSection(page), + page => new ui.sceneobjects.ObjectSingleUserComponentSection(page))); + + // dynamic component sections + + reg.addExtension(new ui.editor.properties.DynamicUserComponentSectionExtension()); + + // more property sections + + reg.addExtension(new ui.editor.properties.SceneEditorPropertySectionExtension( page => new ui.sceneobjects.ListVariableSection(page), page => new ui.sceneobjects.GameObjectListSection(page), page => new ui.sceneobjects.ChildrenSection(page), @@ -401,7 +409,6 @@ namespace phasereditor2d.scene { page => new ui.sceneobjects.ArcadeGeometrySection(page), page => new ui.sceneobjects.ArcadeBodyMovementSection(page), page => new ui.sceneobjects.ArcadeBodyCollisionSection(page), - page => new ui.sceneobjects.TextureSection(page), page => new ui.sceneobjects.TextContentSection(page), page => new ui.sceneobjects.TextSection(page), page => new ui.sceneobjects.BitmapTextSection(page), @@ -416,7 +423,8 @@ namespace phasereditor2d.scene { page => new ui.sceneobjects.TriangleSection(page), page => new ui.sceneobjects.PolygonSection(page), page => new ui.sceneobjects.ColliderSection(page), - page => new ui.sceneobjects.KeyboardKeySection(page) + page => new ui.sceneobjects.KeyboardKeySection(page), + page => new ui.sceneobjects.TextureSection(page), )); // scene tools diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts new file mode 100644 index 000000000..c482340d2 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts @@ -0,0 +1,307 @@ +/// +namespace phasereditor2d.scene.ui.editor.properties { + + import controls = colibri.ui.controls; + import io = colibri.core.io; + + export class DynamicPropertySection extends sceneobjects.SceneGameObjectSection { + + private _componentName: string; + + constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { + super(page, + DynamicPropertySection.computeId(componentName, hash), + `${componentName} (component)`); + + this._componentName = componentName; + } + + private static computeId(compName: string, hash: string) { + + return `phasereditor2d.scene.ui.editor.properties.DynamicPropertySection_${compName}_${hash}`; + } + + createMenu(menu: controls.Menu): void { + + const obj = this.getSelectionFirstElement(); + const objES = obj.getEditorSupport(); + + menu.addAction({ + text: `Select Objects With ${this._componentName}`, + callback: () => { + + const sel = []; + + this.getEditor().getScene().visitAll(obj => { + + if (sceneobjects.GameObjectEditorSupport.hasObjectComponent(obj, sceneobjects.UserComponentsEditorComponent)) { + + const userComp = sceneobjects.GameObjectEditorSupport + .getObjectComponent(obj, sceneobjects.UserComponentsEditorComponent) as sceneobjects.UserComponentsEditorComponent; + + if (userComp.hasUserComponent(this._componentName)) { + + sel.push(obj); + } + } + }); + + this.getEditor().setSelection(sel); + } + }); + + menu.addAction({ + text: "Open Definition Of " + this._componentName, + callback: () => this.openComponentEditor() + }); + + // the Reveal In Prefab File options + { + + const prefabFiles: io.FilePath[] = []; + + for (const obj of this.getSelection()) { + + const objES = obj.getEditorSupport(); + + if (objES.isPrefabInstance()) { + + const file = objES.getPrefabFile(); + + if (prefabFiles.indexOf(file) < 0) { + + prefabFiles.push(file); + } + } + } + + for (const prefabFile of prefabFiles) { + + menu.addAction({ + text: `Reveal In ${prefabFile.getNameWithoutExtension()} File`, + callback: () => this.openPrefabLinkInSceneEditor(prefabFile) + }); + } + } + + const allLocalNodes = this.getSelection() + .map(obj => obj.getEditorSupport() + .getUserComponentsComponent() + .hasLocalUserComponent(this._componentName)) + .length === this.getSelection().length; + + if (allLocalNodes) { + + if (this.getSelection().length === 1) { + + const editorComp = objES.getUserComponentsComponent(); + + menu.addAction({ + text: "Move Up", + callback: () => { + + this.runOperation(() => { + + editorComp.moveUpUserComponent(this._componentName) + }); + + this.updateWithSelection(); + } + }); + + menu.addAction({ + text: "Move Down", + callback: () => { + + this.runOperation(() => { + + editorComp.moveDownUserComponent(this._componentName) + }); + + this.updateWithSelection(); + } + }); + } + + + menu.addAction({ + text: "Delete", + callback: () => { + + const editor = this.getEditor(); + + const selIds = editor.getSelectionManager().getSelectionIds(); + + this.runOperation(() => { + + for (const obj of this.getSelection()) { + + const objEs = obj.getEditorSupport(); + objEs.getUserComponentsComponent() + .removeUserComponent(this._componentName); + } + }); + + editor.getSelectionManager().setSelectionByIds(selIds); + } + }); + } + } + + private runOperation(action: () => void) { + + const editor = this.getEditor(); + + editor.getUndoManager().add(new ui.editor.undo.SimpleSceneSnapshotOperation(editor, action)); + } + + private openPrefabLinkInSceneEditor(prefabFile: io.FilePath) { + + const prefabEditor = colibri.Platform.getWorkbench().openEditor(prefabFile); + + if (prefabEditor && prefabEditor instanceof ui.editor.SceneEditor) { + + setTimeout(() => { + + const obj = this.getSelectionFirstElement(); + const objES = obj.getEditorSupport(); + + let selObj: sceneobjects.ISceneGameObject; + + if (objES.isNestedPrefabInstance()) { + + selObj = prefabEditor.getScene().getByEditorId(objES.getPrefabId()); + + } else { + + selObj = prefabEditor.getScene().getPrefabObject(); + } + + if (selObj) { + + prefabEditor.setSelection([selObj]); + } + + }, 10); + } + } + + + private openComponentEditor() { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const info = finder.getUserComponentByName(this._componentName); + + const editor = colibri.Platform.getWorkbench().openEditor(info.file) as editor.usercomponent.UserComponentsEditor; + + editor.revealComponent(this._componentName); + } + + createForm(parent: HTMLDivElement) { + + const comp = this.createGridElement(parent); + comp.style.gridTemplateColumns = "auto auto 1fr"; + + { + // export property + + const result = this.createBooleanField(comp, this.getExportProperty(), false); + result.labelElement.style.gridColumn = "2"; + + this.addUpdater(() => { + + const values = this.getSelection().map(obj => { + + const objES = obj.getEditorSupport(); + + if (objES.isScenePrefabObject()) { + + if (objES.getUserComponentsComponent() + .hasLocalUserComponent(this._componentName)) { + + return true; + } + } + + return false; + }) + + const visible = this.flatValues_BooleanAnd(values); + + result.labelElement.style.display = visible ? "" : "none"; + result.checkElement.style.display = visible ? "" : "none"; + }); + } + + // user properties + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const compInfo = finder.getUserComponentByName(this._componentName); + + { + const props = compInfo.component.getUserProperties().getProperties(); + + if (props.length > 0) { + + const atLeastOnePrefab = this.getSelection() + .filter(obj => obj.getEditorSupport().isPrefabInstance()) + .length > 0; + + for (const prop of props) { + + prop.getType().createInspectorPropertyEditor(this, comp, prop, atLeastOnePrefab); + } + } + } + } + + private getExportProperty(): sceneobjects.IProperty { + + return { + name: "isExported", + label: "Export", + getValue: obj => { + + const value = obj.getEditorSupport() + .getUserComponentsComponent().isExportComponent(this._componentName); + + return value; + }, + setValue: (obj: sceneobjects.ISceneGameObject, value: boolean) => { + + const compName = this._componentName; + + obj.getEditorSupport() + .getUserComponentsComponent() + .setExportComponent(compName, value); + }, + defValue: true, + }; + } + + canEdit(obj: any, n: number): boolean { + + if (sceneobjects.isGameObject(obj)) { + + const objES = sceneobjects.GameObjectEditorSupport.getEditorSupport(obj); + + const userComp = objES.getUserComponentsComponent(); + + if (userComp.hasUserComponent(this._componentName)) { + + return true; + } + } + + return false; + } + + canEditNumber(n: number): boolean { + + return n > 0; + } + + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts new file mode 100644 index 000000000..70412e4aa --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts @@ -0,0 +1,24 @@ +/// +namespace phasereditor2d.scene.ui.editor.properties { + + export class DynamicUserComponentSectionExtension extends SceneEditorPropertySectionExtension { + + getSectionProviders(): GetPropertySection[] { + + const result: GetPropertySection[] = []; + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + for (const model of finder.getUserComponentsModels()) { + + for (const comp of model.model.getComponents()) { + + result.push(page => new DynamicPropertySection( + page, comp.getName(), `${model.file.getModTime()}`)); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts index 1b2d315e3..7fc8d51fb 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts @@ -34,7 +34,9 @@ namespace phasereditor2d.scene.ui.editor.properties { for (const ext of exts) { - for (const provider of ext.getSectionProviders()) { + const providers = ext.getSectionProviders(); + + for (const provider of providers) { sections.push(provider(page)); } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/texture/TextureSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/texture/TextureSection.ts index 1a13d4aca..9cf1ed92c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/texture/TextureSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/texture/TextureSection.ts @@ -7,7 +7,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { static SECTION_ID = "phasereditor2d.scene.ui.sceneobjects.TextureSection"; constructor(page: controls.properties.PropertyPage) { - super(page, TextureSection.SECTION_ID, "Texture", false, true); + super(page, TextureSection.SECTION_ID, "Texture", false, false); } getSectionHelpPath() { From 571dc24639806a4240b6354242715d4c0338ec85 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 22:59:27 -0400 Subject: [PATCH 38/72] Renames the Scripts menu to Scripting and add the user component commands. --- .../src/ui/editor/SceneEditorMenuCreator.ts | 10 +- .../ui/editor/commands/SceneEditorCommands.ts | 144 ++++++++++++++++++ 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts index 717a32951..fb7cb4851 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts @@ -27,7 +27,7 @@ namespace phasereditor2d.scene.ui.editor { menu.addMenu(this.createPrefabMenu()); - menu.addMenu(this.createScriptsMenu()); + menu.addMenu(this.createScriptingMenu()); menu.addMenu(this.createTypeMenu()); @@ -52,13 +52,17 @@ namespace phasereditor2d.scene.ui.editor { menu.addMenu(this.createCompilerMenu()); } - createScriptsMenu(): controls.Menu { + createScriptingMenu(): controls.Menu { - const menu = new controls.Menu("Scripts"); + const menu = new controls.Menu("Scripting"); menu.addCommand(commands.CMD_OPEN_ADD_SCRIPT_DIALOG); menu.addCommand(commands.CMD_OPEN_SCRIPT_DIALOG); + menu.addSeparator(); + + menu.addCommand(commands.CMD_ADD_USER_COMPONENT); + return menu; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index f99b3e53d..aa673a78b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -65,6 +65,7 @@ namespace phasereditor2d.scene.ui.editor.commands { export const CMD_SORT_OBJ_DOWN = "phasereditor2d.scene.ui.editor.commands.SortObjectDown"; export const CMD_SORT_OBJ_TOP = "phasereditor2d.scene.ui.editor.commands.SortObjectTop"; export const CMD_SORT_OBJ_BOTTOM = "phasereditor2d.scene.ui.editor.commands.SortObjectBottom"; + export const CMD_ADD_USER_COMPONENT = "phasereditor2d.scene.ui.editor.commands.AddUserComponent"; function isSceneScope(args: colibri.ui.ide.commands.HandlerArgs) { @@ -114,6 +115,24 @@ namespace phasereditor2d.scene.ui.editor.commands { return args.activeEditor && args.activeEditor.getSelection().length > 0; } + function onlyGameObjectsSelected(args: colibri.ui.ide.commands.HandlerArgs) { + + if (args.activeEditor instanceof SceneEditor) { + + for (const obj of args.activeEditor.getSelection()) { + + if (!sceneobjects.isGameObject(obj)) { + + return false; + } + } + + return args.activeEditor.getSelection().length > 0; + } + + return false; + } + export class SceneEditorCommands { static registerCommands(manager: colibri.ui.ide.commands.CommandManager) { @@ -161,6 +180,8 @@ namespace phasereditor2d.scene.ui.editor.commands { this.registerScriptNodeCommands(manager); + this.registerUserComponentCommands(manager); + this.registerPrefabCommands(manager); this.registerPropertiesCommands(manager); @@ -229,6 +250,129 @@ namespace phasereditor2d.scene.ui.editor.commands { }) } + private static registerUserComponentCommands(manager: colibri.ui.ide.commands.CommandManager) { + + manager.add({ + + command: { + id: CMD_ADD_USER_COMPONENT, + category: CAT_SCENE_EDITOR, + name: "Add User Component", + tooltip: "Pick a User Component and add it to the selected objects" + }, + handler: { + testFunc: onlyGameObjectsSelected, + executeFunc: args => { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + const editor = args.activeEditor as SceneEditor; + + const editorCompList = args.activeEditor.getSelection() + .map(obj => sceneobjects.GameObjectEditorSupport.getObjectComponent(obj, sceneobjects.UserComponentsEditorComponent) as sceneobjects.UserComponentsEditorComponent); + + const used = new Set( + [...editorCompList + .flatMap(editorComp => editorComp.getLocalUserComponents()) + .map(info => info.component.getName()), + + ...editorCompList.flatMap(editorComp => editorComp.getPrefabUserComponents()) + .flatMap(info => info.components) + .map(c => c.getName()) + ] + ); + + class ContentProvider implements controls.viewers.ITreeContentProvider { + + getRoots(input: any): any[] { + + return finder.getUserComponentsModels() + .filter(info => info.model.getComponents().filter(c => !used.has(c.getName())).length > 0); + } + + getChildren(parentObj: core.json.IUserComponentsModelInfo | usercomponent.UserComponent): any[] { + + if (parentObj instanceof usercomponent.UserComponent) { + + return []; + } + + return parentObj.model.getComponents().filter(c => !used.has(c.getName())); + } + } + + const viewer = new controls.viewers.TreeViewer("UserComponentInstancePropertySection.addComponentDialogViewer"); + + viewer.setStyledLabelProvider({ + getStyledTexts: (obj: usercomponent.UserComponent | core.json.IUserComponentsModelInfo, dark) => { + + const theme = controls.Controls.getTheme(); + + if (obj instanceof usercomponent.UserComponent) { + + return [{ + text: obj.getName(), + color: theme.viewerForeground + }]; + } + + return [{ + text: obj.file.getNameWithoutExtension(), + color: theme.viewerForeground + }, { + text: " - " + obj.file.getParent().getProjectRelativeName() + .split("/").filter(s => s !== "").reverse().join("/"), + color: theme.viewerForeground + "90" + }]; + } + }); + + viewer.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider( + (obj: core.json.IUserComponentsModelInfo | usercomponent.UserComponent) => + new controls.viewers.IconImageCellRenderer( + obj instanceof usercomponent.UserComponent ? + ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT) + : colibri.ColibriPlugin.getInstance().getIcon(colibri.ICON_FOLDER)))); + + viewer.setContentProvider(new ContentProvider()); + + viewer.setInput([]); + + viewer.expandRoots(false); + + const dlg = new controls.dialogs.ViewerDialog(viewer, false); + + dlg.setSize(undefined, 400, true); + + dlg.create(); + + dlg.setTitle("User Component"); + + dlg.enableButtonOnlyWhenOneElementIsSelected(dlg.addOpenButton("Add Component", () => { + + const selComp = viewer.getSelectionFirstElement() as usercomponent.UserComponent; + + if (selComp) { + + + editor.getUndoManager().add(new ui.editor.undo.SimpleSceneSnapshotOperation(editor, () => { + + for (const editorComp of editorCompList) { + + editorComp.addUserComponent(selComp.getName()); + } + })); + + // section.updateWithSelection(); + editor.dispatchSelectionChanged(); + } + }), obj => obj instanceof usercomponent.UserComponent); + + dlg.addCancelButton(); + } + } + }); + } + private static registerScriptNodeCommands(manager: colibri.ui.ide.commands.CommandManager) { manager.add({ From df8eff2174400a2bc105bb31351ee358125100af Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 23:10:54 -0400 Subject: [PATCH 39/72] Removes the User Components section in the scene editor. --- CHANGELOG.MD | 3 + .../phasereditor2d.scene/src/ScenePlugin.ts | 7 +- .../ObjectSingleUserComponentSection.ts | 497 ------------------ .../properties/ObjectUserComponentsSection.ts | 260 --------- 4 files changed, 6 insertions(+), 761 deletions(-) delete mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectSingleUserComponentSection.ts delete mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectUserComponentsSection.ts diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 7384e4133..8df67597d 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -13,6 +13,9 @@ * Shows Keyboard.Key and Object List objects in the Object Variable user property's dialog.. * Adds the new KeyCode User Property. * Fixes hit area serialization. +* Removes the User Components section and show user components properties as individual sections: + * Renames the Scripts context menu to Scripting and include: + - Add User Component ## v3.61.0 - May 18, 2023 diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index 84cc1a43a..604b509ea 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -373,16 +373,15 @@ namespace phasereditor2d.scene { page => new ui.sceneobjects.GameObjectVariableSection(page), page => new ui.sceneobjects.PrefabObjectVariableSection(page), page => new ui.sceneobjects.NestedPrefabObjectVariableSection(page), - page => new ui.sceneobjects.PrefabInstanceSection(page), - page => new ui.sceneobjects.ObjectUserComponentsSection(page), - page => new ui.sceneobjects.ObjectSingleUserComponentSection(page))); + page => new ui.sceneobjects.PrefabInstanceSection(page) + )); // dynamic component sections reg.addExtension(new ui.editor.properties.DynamicUserComponentSectionExtension()); // more property sections - + reg.addExtension(new ui.editor.properties.SceneEditorPropertySectionExtension( page => new ui.sceneobjects.ListVariableSection(page), page => new ui.sceneobjects.GameObjectListSection(page), diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectSingleUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectSingleUserComponentSection.ts deleted file mode 100644 index d0e4f5e8b..000000000 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectSingleUserComponentSection.ts +++ /dev/null @@ -1,497 +0,0 @@ -namespace phasereditor2d.scene.ui.sceneobjects { - - import controls = colibri.ui.controls; - import io = colibri.core.io; - - class GameObjectSectionAdapter extends SceneGameObjectSection { - - constructor(page: controls.properties.PropertyPage) { - super(page, "id", "title"); - } - - createForm(parent: HTMLDivElement) { - // nothing - } - - canEdit(obj: any, n: number): boolean { - // nothing - return false; - } - - canEditNumber(n: number): boolean { - // nothing - return false; - } - - getSelection(): ISceneGameObject[] { - - const page = this.getPage(); - - const sel = page.getSelection(); - - return sel.map((n: UserComponentNode) => n.getObject()); - } - } - - export class ObjectSingleUserComponentSection extends editor.properties.BaseSceneSection { - - private _propArea: HTMLDivElement; - - constructor(page: controls.properties.PropertyPage) { - super(page, - "phasereditor2d.scene.ui.sceneobjects.ObjectSingleUserComponentSection", "User Component", false, false); - } - - getSectionHelpPath() { - return "scene-editor/user-components-instancing.html"; - } - - createForm(parent: HTMLDivElement) { - - const sectionAdapter = new GameObjectSectionAdapter(this.getPage()); - - { - const commonPropsComp = this.createGridElement(parent, 2); - - { - // name property - - this.createLabel(commonPropsComp, "Component"); - - const text = this.createText(commonPropsComp, true); - - this.addUpdater(() => { - - text.value = this.buildComponentName(); - }); - } - - { - // export property - - const result = sectionAdapter.createBooleanField(commonPropsComp, this.getExportProperty(), false); - - this.addUpdater(() => { - - const values = this.getSelection().map(n => { - - if (n.getObject().getEditorSupport().isScenePrefabObject()) { - - if (n.getUserComponentsComponent().hasLocalUserComponent(n.getComponentName())) { - - return true; - } - } - - return false; - }); - - const visible = this.flatValues_BooleanAnd(values); - - result.labelElement.style.display = visible ? "" : "none"; - result.checkElement.style.display = visible ? "" : "none"; - }); - } - } - - this._propArea = this.createGridElement(parent); - this._propArea.style.gridTemplateColumns = "1fr"; - - this.addUpdater(() => { - - this._propArea.innerHTML = ""; - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - const nodes = this.getSelection(); - const node = nodes[0]; - - const compName = node.getComponentName(); - const compInfo = finder.getUserComponentByName(compName); - - // properties - - { - const props = compInfo.component.getUserProperties().getProperties(); - - if (props.length > 0) { - - const compPropArea = this.createGridElement(this._propArea); - compPropArea.style.gridTemplateColumns = "auto auto 1fr"; - - const atLeastOneDefinedInAPrefab = nodes - .filter(n => n.isPrefabDefined()) - .length > 0; - - for (const prop of props) { - - prop.getType().createInspectorPropertyEditor(sectionAdapter, compPropArea, prop, atLeastOneDefinedInAPrefab); - } - } - } - - const btn = this.createButton(this._propArea, "Select Parent Game Object", () => { - - this.getEditor().setSelection(this.getSelection().map(node => node.getObject())); - }); - btn.style.width = "100%"; - btn.style.justifySelf = "self-center"; - btn.style.marginTop = "10px"; - }); - - // it is important to update the adapter at the end, - // because it should update the adapter selection after the dynamic prop elements - // are created - - this.addUpdater(() => { - - sectionAdapter.updateWithSelection(); - }); - } - - private getExportProperty(): IProperty { - - return { - name: "isExported", - label: "Export", - getValue: obj => { - - const compName = this.getSelectionFirstElement().getComponentName(); - - const value = obj.getEditorSupport() - .getUserComponentsComponent().isExportComponent(compName); - - return value; - }, - setValue: (obj: ISceneGameObject, value: boolean) => { - - const compName = this.getSelectionFirstElement().getComponentName(); - - obj.getEditorSupport() - .getUserComponentsComponent().setExportComponent(compName, value); - }, - defValue: true, - }; - } - - private static openComponentEditor(node: UserComponentNode) { - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - const compName = node.getComponentName(); - - const info = finder.getUserComponentByName(compName); - - const editor = colibri.Platform.getWorkbench().openEditor(info.file) as editor.usercomponent.UserComponentsEditor; - - editor.revealComponent(compName); - } - - static createComponentIcon(section: colibri.ui.controls.properties.FormBuilder, headerDiv: HTMLDivElement) { - - section.createIcon(headerDiv, ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT)); - } - - static selectAllComponentNodesFor(editor: ui.editor.SceneEditor, node: UserComponentNode) { - - const compName = node.getComponentName(); - - const nodes = editor.getSelectedGameObjects() - .flatMap(obj => obj.getEditorSupport() - .getUserComponentsComponent().getUserComponentNodes()) - .filter(node => node.getComponentName() === compName); - - editor.setSelection(nodes); - } - - private static openPrefabLinkInSceneEditor(node: UserComponentNode) { - - const prefabFile = node.getPrefabFile(); - const prefabEditor = colibri.Platform.getWorkbench().openEditor(prefabFile); - - if (prefabEditor && prefabEditor instanceof ui.editor.SceneEditor) { - - setTimeout(() => { - - const obj = node.getObject(); - const objES = obj.getEditorSupport(); - - let selObj: ISceneGameObject; - - if (objES.isNestedPrefabInstance()) { - - selObj = prefabEditor.getScene().getByEditorId(objES.getPrefabId()); - - } else { - - selObj = prefabEditor.getScene().getPrefabObject(); - } - - if (selObj) { - - const selNode = selObj.getEditorSupport().getUserComponentsComponent().getUserComponentNodes().find(n => n.getComponentName() === node.getComponentName()); - - if (selNode) { - - prefabEditor.setSelection([selNode]); - } - } - - }, 10); - } - } - - private buildComponentName() { - - const nodes = this.getSelection(); - - let name = this.getSelectionFirstElement().getComponentName(); - - const prefabNodes = [...new Set( - nodes - .filter(n => n.isPrefabDefined()) - .map(node => node.getPrefabFile().getNameWithoutExtension())) - ]; - - const prefabNames = prefabNodes.join(", "); - - if (prefabNodes.length === 1) { - - name += " ← " + prefabNames; - - } else if (prefabNodes.length > 1) { - - name += ` ← (${prefabNames})`; - } - - return name; - } - - static buildPrefabLinks(nodes: UserComponentNode[], headerDiv: HTMLDivElement) { - - const nodesInPrefabs = nodes.filter(n => n.isPrefabDefined()); - const nodesInPrefabsLen = nodesInPrefabs.length; - const atLeastOneDefinedInAPrefab = nodesInPrefabsLen > 0; - - if (atLeastOneDefinedInAPrefab) { - - const elem = document.createElement("span"); - elem.innerHTML = " ← "; - headerDiv.appendChild(elem); - - if (nodesInPrefabsLen > 1) { - - const elem = document.createElement("label"); - elem.innerHTML = "("; - headerDiv.appendChild(elem); - } - - for (let i = 0; i < nodesInPrefabsLen; i++) { - - const node = nodesInPrefabs[i]; - - const prefabFile = nodesInPrefabs[i].getPrefabFile(); - const prefabBtn = document.createElement("a"); - headerDiv.appendChild(prefabBtn); - prefabBtn.href = "#"; - prefabBtn.innerHTML = prefabFile.getNameWithoutExtension(); - prefabBtn.addEventListener("click", e => { - - this.openPrefabLinkInSceneEditor(node); - }); - - if (i < nodesInPrefabsLen - 1) { - - const elem = document.createElement("label"); - elem.innerHTML = ", "; - headerDiv.appendChild(elem); - } - } - - if (nodesInPrefabs.length > 1) { - - const elem = document.createElement("label"); - elem.innerHTML = ")"; - headerDiv.appendChild(elem); - } - } - return { atLeastOneDefinedInAPrefab }; - } - - static createComponentMenu( - nodes: UserComponentNode[], - menu: controls.Menu, - section: ObjectSingleUserComponentSection | ObjectUserComponentsSection) { - - const firstNode = nodes[0]; - const comp = firstNode.getUserComponent(); - const compName = comp.getName(); - - menu.addAction({ - text: `Select Objects With ${compName}`, - callback: () => { - - const sel = []; - - section.getEditor().getScene().visitAll(obj => { - - if (GameObjectEditorSupport.hasObjectComponent(obj, UserComponentsEditorComponent)) { - - const userComp = GameObjectEditorSupport - .getObjectComponent(obj, UserComponentsEditorComponent) as UserComponentsEditorComponent; - - if (userComp.hasUserComponent(compName)) { - - sel.push(obj); - } - } - }); - - section.getEditor().setSelection(sel); - } - }); - - menu.addAction({ - text: "Open Definition Of " + firstNode.getComponentName(), - callback: () => this.openComponentEditor(firstNode) - }); - - // the Reveal In Prefab File options - { - const fileNodeMap = new Map(); - - for (const node of nodes) { - - if (node.isPrefabDefined()) { - - fileNodeMap.set(node.getPrefabFile(), node); - } - } - - for (const prefabFile of fileNodeMap.keys()) { - - const node = fileNodeMap.get(prefabFile); - - menu.addAction({ - text: `Reveal In ${prefabFile.getNameWithoutExtension()} File`, - callback: () => this.openPrefabLinkInSceneEditor(node) - }); - } - } - - if (section instanceof ObjectUserComponentsSection) { - - menu.addAction({ - text: "Edit Values", - callback: () => { - - ObjectSingleUserComponentSection.selectAllComponentNodesFor(section.getEditor(), firstNode); - } - }); - } - - if (!firstNode.isPrefabDefined()) { - - if (nodes.length === 1) { - - const editorComp = firstNode.getUserComponentsComponent(); - - menu.addAction({ - text: "Move Up", - callback: () => { - - section.runOperation(() => { - - editorComp.moveUpUserComponent(compName) - }); - - section.updateWithSelection(); - } - }); - - menu.addAction({ - text: "Move Down", - callback: () => { - - section.runOperation(() => { - - editorComp.moveDownUserComponent(compName) - }); - - section.updateWithSelection(); - } - }); - } - - const allLocalNodes = nodes.filter(n => n.isPrefabDefined()).length === 0; - - if (allLocalNodes) { - - menu.addAction({ - text: "Delete", - callback: () => { - - const editor = section.getEditor(); - - const selIds = editor.getSelectionManager().getSelectionIds(); - - section.runOperation(() => { - - for (const node of nodes) { - - node.getUserComponentsComponent().removeUserComponent(compName); - } - }); - - editor.getSelectionManager().setSelectionByIds(selIds); - } - }); - } - } - } - - createMenu(menu: controls.Menu): void { - - ObjectSingleUserComponentSection.createComponentMenu(this.getSelection(), menu, this); - - menu.addSeparator(); - - super.createMenu(menu); - } - - runOperation(action: () => void) { - - const editor = this.getEditor(); - - editor.getUndoManager().add(new ui.editor.undo.SimpleSceneSnapshotOperation(editor, action)); - } - - canEditAll(selection: UserComponentNode[]) { - - const first = selection[0]; - const firstComp = first.getUserComponent(); - - for (const node of selection) { - - const comp = node.getUserComponent(); - - if (comp.getName() !== firstComp.getName()) { - - return false; - } - } - - return true; - } - - canEdit(obj: any, n: number): boolean { - - return obj instanceof sceneobjects.UserComponentNode; - } - - canEditNumber(n: number): boolean { - - return n > 0; - } - } -} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectUserComponentsSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectUserComponentsSection.ts deleted file mode 100644 index 4d0cb8f55..000000000 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/ObjectUserComponentsSection.ts +++ /dev/null @@ -1,260 +0,0 @@ -namespace phasereditor2d.scene.ui.sceneobjects { - - import controls = colibri.ui.controls; - import UserComponent = editor.usercomponent.UserComponent; - - export class ObjectUserComponentsSection extends SceneGameObjectSection { - - private _propArea: HTMLDivElement; - - constructor(page: controls.properties.PropertyPage) { - super(page, - "phasereditor2d.scene.ui.sceneobjects.ObjectUserComponentsSection", "User Components", false, true); - } - - getSectionHelpPath() { - return "scene-editor/user-components-instancing.html"; - } - - private getCommonComponentNodes() { - - const nameCountMap = new Map(); - - let selection = this.getSelection() - .flatMap(obj => obj.getEditorSupport().getUserComponentsComponent().getUserComponentNodes()); - - let nodes: UserComponentNode[] = []; - - for (const node of selection) { - - if (!node.isPublished()) { - - continue; - } - - const name = node.getComponentName(); - - if (nameCountMap.has(name)) { - - const count = nameCountMap.get(name); - nameCountMap.set(name, count + 1); - - } else { - - nameCountMap.set(name, 1); - nodes.push(node); - } - } - - const total = this.getSelection().length; - - nodes = nodes - .filter(node => nameCountMap.get(node.getComponentName()) === total); - - nodes.sort((a, b) => { - - const aa = a.isPrefabDefined() ? 1 : 0; - const bb = b.isPrefabDefined() ? 1 : 0; - - return aa - bb; - }); - - return nodes; - } - - createForm(parent: HTMLDivElement) { - - const comp = this.createGridElement(parent); - comp.style.gridTemplateColumns = "1fr"; - - this._propArea = this.createGridElement(comp); - this._propArea.style.gridTemplateColumns = "1fr"; - - comp.appendChild(this._propArea); - - this.addUpdater(() => { - - this._propArea.innerHTML = ""; - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - const editorCompList = this.getSelection() - .map(obj => GameObjectEditorSupport.getObjectComponent(obj, UserComponentsEditorComponent) as UserComponentsEditorComponent); - - const commonNodes = this.getCommonComponentNodes(); - - for (const node of commonNodes) { - - const compName = node.getComponentName(); - - const headerDiv = document.createElement("div"); - headerDiv.classList.add("PrefabLink"); - - this._propArea.appendChild(headerDiv); - - ObjectSingleUserComponentSection.createComponentIcon(this, headerDiv); - - const compBtn = document.createElement("a"); - headerDiv.appendChild(compBtn); - compBtn.href = "#"; - compBtn.innerHTML = compName; - compBtn.addEventListener("click", e => { - - ObjectSingleUserComponentSection.selectAllComponentNodesFor(this.getEditor(), node); - }); - - // get all nodes (from the selected objects) - // with the same user component of this current node - const sameNodes = this.getSelection() - .flatMap(obj => obj.getEditorSupport() - .getUserComponentsComponent().getUserComponentNodes()) - .filter(n => n.getComponentName() === compName); - - const samePrefabNodes = sameNodes.filter(n => n.isPrefabDefined()); - - ObjectSingleUserComponentSection.buildPrefabLinks(samePrefabNodes, headerDiv); - - - this.createComponentMenuIcon(headerDiv, sameNodes); - } - - // Add Components button - - const btn = this.createButton(this._propArea, "Add Component", () => { - - const used = new Set( - [...editorCompList - .flatMap(editorComp => editorComp.getLocalUserComponents()) - .map(info => info.component.getName()), - - ...editorCompList.flatMap(editorComp => editorComp.getPrefabUserComponents()) - .flatMap(info => info.components) - .map(c => c.getName()) - ] - ); - - class ContentProvider implements controls.viewers.ITreeContentProvider { - - getRoots(input: any): any[] { - - return finder.getUserComponentsModels() - .filter(info => info.model.getComponents().filter(c => !used.has(c.getName())).length > 0); - } - - getChildren(parentObj: core.json.IUserComponentsModelInfo | UserComponent): any[] { - - if (parentObj instanceof UserComponent) { - - return []; - } - - return parentObj.model.getComponents().filter(c => !used.has(c.getName())); - } - } - - const viewer = new controls.viewers.TreeViewer("UserComponentInstancePropertySection.addComponentDialogViewer"); - - viewer.setStyledLabelProvider({ - getStyledTexts: (obj: UserComponent | core.json.IUserComponentsModelInfo, dark) => { - - const theme = controls.Controls.getTheme(); - - if (obj instanceof UserComponent) { - - return [{ - text: obj.getName(), - color: theme.viewerForeground - }]; - } - - return [{ - text: obj.file.getNameWithoutExtension(), - color: theme.viewerForeground - }, { - text: " - " + obj.file.getParent().getProjectRelativeName() - .split("/").filter(s => s !== "").reverse().join("/"), - color: theme.viewerForeground + "90" - }]; - } - }); - - viewer.setCellRendererProvider(new controls.viewers.EmptyCellRendererProvider( - (obj: core.json.IUserComponentsModelInfo | UserComponent) => - new controls.viewers.IconImageCellRenderer( - obj instanceof UserComponent ? - ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT) - : colibri.ColibriPlugin.getInstance().getIcon(colibri.ICON_FOLDER)))); - - viewer.setContentProvider(new ContentProvider()); - - viewer.setInput([]); - - viewer.expandRoots(false); - - const dlg = new controls.dialogs.ViewerDialog(viewer, false); - - dlg.setSize(undefined, 400, true); - - dlg.create(); - - dlg.setTitle("User Component"); - - dlg.enableButtonOnlyWhenOneElementIsSelected(dlg.addOpenButton("Add Component", () => { - - const selComp = viewer.getSelectionFirstElement() as UserComponent; - - if (selComp) { - - this.runOperation(() => { - - for (const editorComp of editorCompList) { - - editorComp.addUserComponent(selComp.getName()); - } - }); - - this.updateWithSelection(); - } - }), obj => obj instanceof UserComponent); - - dlg.addCancelButton(); - }); - - btn.style.width = "100%"; - btn.style.justifySelf = "self-center"; - btn.style.marginTop = "10px"; - }); - } - - private createComponentMenuIcon( - headerDiv: HTMLElement, nodes: UserComponentNode[]) { - - this.createMenuIcon(headerDiv, () => { - - const menu = new controls.Menu(); - - ObjectSingleUserComponentSection.createComponentMenu(nodes, menu, this); - - return menu; - }); - } - - runOperation(action: () => void) { - - const editor = this.getEditor(); - - editor.getUndoManager().add(new ui.editor.undo.SimpleSceneSnapshotOperation(editor, action)); - } - - canEdit(obj: any, n: number): boolean { - - return GameObjectEditorSupport.hasEditorSupport(obj) - && (obj as ISceneGameObject).getEditorSupport().isDisplayObject(); - } - - canEditNumber(n: number): boolean { - - return n > 0; - } - } -} \ No newline at end of file From a9a70d374654d4ff629a853bcebaf2d728c7624c Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 23:14:51 -0400 Subject: [PATCH 40/72] A small change. --- .../src/ui/editor/properties/DynamicComponentSection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts index c482340d2..327f24985 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts @@ -11,7 +11,7 @@ namespace phasereditor2d.scene.ui.editor.properties { constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, DynamicPropertySection.computeId(componentName, hash), - `${componentName} (component)`); + `${componentName} (user component)`); this._componentName = componentName; } From 0dcf3aa33d81c4ad6b363706832096b072b86e3c Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 23:18:10 -0400 Subject: [PATCH 41/72] Binds `KeyC` to the add user component command. --- .../src/ui/editor/commands/SceneEditorCommands.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index aa673a78b..d07f4ce6c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -260,6 +260,10 @@ namespace phasereditor2d.scene.ui.editor.commands { name: "Add User Component", tooltip: "Pick a User Component and add it to the selected objects" }, + keys: { + key: "KeyC", + keyLabel: "C" + }, handler: { testFunc: onlyGameObjectsSelected, executeFunc: args => { @@ -345,7 +349,7 @@ namespace phasereditor2d.scene.ui.editor.commands { dlg.create(); - dlg.setTitle("User Component"); + dlg.setTitle("Add User Component"); dlg.enableButtonOnlyWhenOneElementIsSelected(dlg.addOpenButton("Add Component", () => { From ab098de9d93b07ae6c7a144b39c43607413752d0 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 19 Jun 2023 23:21:02 -0400 Subject: [PATCH 42/72] Renames "Add Prefab Property" to "Add Property" in common user property dialog. --- .../src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts index ef41d82e4..460198a55 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/dialogs/AbstractAddPrefabPropertyDialog.ts @@ -14,7 +14,7 @@ namespace phasereditor2d.scene.ui.dialogs { super.create(hideParentDialog); - this.setTitle("Add Prefab Property"); + this.setTitle("Add Property"); this.enableButtonOnlyWhenOneElementIsSelected(this.addOpenButton("Add Property", sel => { From 31bd344dd23e6d0c31f35c686e5b302da1cbb078 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 20 Jun 2023 00:32:17 -0400 Subject: [PATCH 43/72] Doesn't show user components as nodes in the Outline view. --- .../outline/SceneEditorOutlineContentProvider.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts index c96c9b86e..33b715930 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts @@ -86,14 +86,14 @@ namespace phasereditor2d.scene.ui.editor.outline { list.reverse(); } - // prepend the user components + // // prepend the user components - const compNodes = parentES - .getUserComponentsComponent() - .getUserComponentNodes() - .filter(n => n.isPublished()); + // const compNodes = parentES + // .getUserComponentsComponent() + // .getUserComponentNodes() + // .filter(n => n.isPublished()); - list = [...compNodes, ...list]; + // list = [...compNodes, ...list]; return list; } From 2d6c38d4d0ba762ffb5279f828f46ae0de30451c Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Tue, 20 Jun 2023 00:32:41 -0400 Subject: [PATCH 44/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 8df67597d..0fc9b5d54 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -16,6 +16,7 @@ * Removes the User Components section and show user components properties as individual sections: * Renames the Scripts context menu to Scripting and include: - Add User Component +* Removes user component nodes from the Outline view. ## v3.61.0 - May 18, 2023 From d8093bbd456dcf73b06eb788f2d37d2d2f624c40 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 11:56:31 -0400 Subject: [PATCH 45/72] Adds Browse User Components command. --- .../src/ui/editor/SceneEditorMenuCreator.ts | 1 + .../ui/editor/commands/SceneEditorCommands.ts | 22 ++++ .../SceneEditorOutlineContentProvider.ts | 21 ++-- .../object/BrowseUserComponentsDialog.ts | 116 ++++++++++++++++++ 4 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/BrowseUserComponentsDialog.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts index fb7cb4851..ff4167fe9 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/SceneEditorMenuCreator.ts @@ -62,6 +62,7 @@ namespace phasereditor2d.scene.ui.editor { menu.addSeparator(); menu.addCommand(commands.CMD_ADD_USER_COMPONENT); + menu.addCommand(commands.CMD_BROWSE_USER_COMPONENTS); return menu; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index d07f4ce6c..2fbd7cbfe 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -66,6 +66,7 @@ namespace phasereditor2d.scene.ui.editor.commands { export const CMD_SORT_OBJ_TOP = "phasereditor2d.scene.ui.editor.commands.SortObjectTop"; export const CMD_SORT_OBJ_BOTTOM = "phasereditor2d.scene.ui.editor.commands.SortObjectBottom"; export const CMD_ADD_USER_COMPONENT = "phasereditor2d.scene.ui.editor.commands.AddUserComponent"; + export const CMD_BROWSE_USER_COMPONENTS = "phasereditor2d.scene.ui.editor.commands.BrowseUserComponents"; function isSceneScope(args: colibri.ui.ide.commands.HandlerArgs) { @@ -252,6 +253,8 @@ namespace phasereditor2d.scene.ui.editor.commands { private static registerUserComponentCommands(manager: colibri.ui.ide.commands.CommandManager) { + // add user component + manager.add({ command: { @@ -375,6 +378,25 @@ namespace phasereditor2d.scene.ui.editor.commands { } } }); + + // browse user component + manager.add({ + command: { + id: CMD_BROWSE_USER_COMPONENTS, + category: CAT_SCENE_EDITOR, + name: "Browse User Components", + tooltip: "Browse all user components in the scene's objects." + }, + handler: { + testFunc: isSceneScope, + executeFunc: args => { + + const dlg = new sceneobjects.BrowseUserComponentsDialog( + args.activeEditor as SceneEditor); + dlg.create(); + } + } + }) } private static registerScriptNodeCommands(manager: colibri.ui.ide.commands.CommandManager) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts index 33b715930..a00a8a16b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/outline/SceneEditorOutlineContentProvider.ts @@ -5,10 +5,12 @@ namespace phasereditor2d.scene.ui.editor.outline { export class SceneEditorOutlineContentProvider implements controls.viewers.ITreeContentProvider { protected _editor: SceneEditor; + private _includeUserComponents: boolean; - constructor(editor: SceneEditor) { + constructor(editor: SceneEditor, includeUserComponents = false) { this._editor = editor; + this._includeUserComponents = includeUserComponents; } getRoots(input: any): any[] { @@ -86,14 +88,17 @@ namespace phasereditor2d.scene.ui.editor.outline { list.reverse(); } - // // prepend the user components + if (this._includeUserComponents) { - // const compNodes = parentES - // .getUserComponentsComponent() - // .getUserComponentNodes() - // .filter(n => n.isPublished()); + // prepend the user components - // list = [...compNodes, ...list]; + const compNodes = parentES + .getUserComponentsComponent() + .getUserComponentNodes() + .filter(n => n.isPublished()); + + list = [...compNodes, ...list]; + } return list; } @@ -113,7 +118,7 @@ namespace phasereditor2d.scene.ui.editor.outline { } else if (parent instanceof sceneobjects.ObjectList) { const scene = this._editor.getScene(); - + return parent.getItemsWithObjects(scene); } else if (typeof parent === "string") { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/BrowseUserComponentsDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/BrowseUserComponentsDialog.ts new file mode 100644 index 000000000..f657b73c6 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/BrowseUserComponentsDialog.ts @@ -0,0 +1,116 @@ +namespace phasereditor2d.scene.ui.sceneobjects { + + import controls = colibri.ui.controls; + + export class BrowseUserComponentsDialog extends controls.dialogs.ViewerDialog { + + private static createViewer(editor: ui.editor.SceneEditor) { + + const viewer = new controls.viewers.TreeViewer("BrowseScriptsDialog"); + + viewer.setLabelProvider(new ui.editor.outline.SceneEditorOutlineLabelProvider()); + viewer.setStyledLabelProvider(new ui.editor.outline.SceneEditorOutlineStyledLabelProvider()); + viewer.setCellRendererProvider(new ui.editor.outline.SceneEditorOutlineRendererProvider()); + viewer.setContentProvider(new UserCompponentsDialogContentProvider(editor)); + viewer.setInput([]) + viewer.expandRoots(); + + return viewer; + } + + private _editor: ui.editor.SceneEditor; + + constructor(editor: ui.editor.SceneEditor) { + super(BrowseUserComponentsDialog.createViewer(editor), true); + + this._editor = editor; + } + + create(): void { + + super.create(); + + this.setTitle("Browse User Components"); + + this.addOpenButton("Select", sel => { + + const selSet = new Set(sel.map(obj => { + + if (obj instanceof sceneobjects.UserComponentNode) { + + return obj.getObject() + } + + return obj; + })); + + + this._editor.setSelection([...selSet]); + }); + + this.addCancelButton(); + } + } + + class UserCompponentsDialogContentProvider extends ui.editor.outline.SceneEditorOutlineContentProvider { + + constructor(editor: ui.editor.SceneEditor) { + super(editor, true); + } + + getRoots(input: any): any[] { + + return [this._editor.getScene().sys.displayList]; + } + + getChildren(parent: any): any[] { + + const children = super.getChildren(parent); + + let result = []; + + for (const obj of children) { + + if (obj instanceof sceneobjects.UserComponentNode) { + + result.push(obj); + + } else if (isGameObject(obj)) { + + if (this.hasUserComponents(obj)) { + + result.push(obj); + } + } + } + + return result; + } + + private hasUserComponents(obj: ISceneGameObject) { + + let result = obj.getEditorSupport().getUserComponentsComponent() + .getUserComponentNodes().length > 0; + + if (!result) { + + const children = super.getChildren(obj); + + for (const child of children) { + + if (isGameObject(child)) { + + result = this.hasUserComponents(child); + + if (result) { + + return true; + } + } + } + } + + return result; + } + } +} \ No newline at end of file From 400c415a41230cd2d97c516aecc0f1b39ea76408 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 11:58:15 -0400 Subject: [PATCH 46/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 0fc9b5d54..26af27558 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -16,6 +16,7 @@ * Removes the User Components section and show user components properties as individual sections: * Renames the Scripts context menu to Scripting and include: - Add User Component + - Browse User Components * Removes user component nodes from the Outline view. ## v3.61.0 - May 18, 2023 From 8907a2bdf84c32a2cd8649c525812cfb51e27cd6 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 12:21:56 -0400 Subject: [PATCH 47/72] Sorts user components in Inspector view following the same order in game object serialization & code generation. --- ...=> DynamicUserComponentPropertySection.ts} | 4 +-- .../DynamicUserComponentSectionExtension.ts | 32 ++++++++++++++++--- .../properties/SceneEditorPopertyProvider.ts | 2 +- .../SceneEditorPropertySectionExtension.ts | 2 +- 4 files changed, 31 insertions(+), 9 deletions(-) rename source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/{DynamicComponentSection.ts => DynamicUserComponentPropertySection.ts} (97%) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts similarity index 97% rename from source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts rename to source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts index 327f24985..30215fe06 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts @@ -4,13 +4,13 @@ namespace phasereditor2d.scene.ui.editor.properties { import controls = colibri.ui.controls; import io = colibri.core.io; - export class DynamicPropertySection extends sceneobjects.SceneGameObjectSection { + export class DynamicUserComponentPropertySection extends sceneobjects.SceneGameObjectSection { private _componentName: string; constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, - DynamicPropertySection.computeId(componentName, hash), + DynamicUserComponentPropertySection.computeId(componentName, hash), `${componentName} (user component)`); this._componentName = componentName; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts index 70412e4aa..97047a16e 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts @@ -3,21 +3,43 @@ namespace phasereditor2d.scene.ui.editor.properties { export class DynamicUserComponentSectionExtension extends SceneEditorPropertySectionExtension { - getSectionProviders(): GetPropertySection[] { + getSectionProviders(editor: SceneEditor): GetPropertySection[] { + + const compNames = editor.getSelectedGameObjects() + .flatMap(obj => obj.getEditorSupport() + .getUserComponentsComponent() + .getUserComponentNodes()) + .map(compNode => compNode.getComponentName()) + + const used = new Set(); const result: GetPropertySection[] = []; const finder = ScenePlugin.getInstance().getSceneFinder(); - for (const model of finder.getUserComponentsModels()) { + for(const compName of compNames) { + + if (!used.has(compName)) { + + const findResult = finder.getUserComponentByName(compName); - for (const comp of model.model.getComponents()) { + if (findResult) { - result.push(page => new DynamicPropertySection( - page, comp.getName(), `${model.file.getModTime()}`)); + result.push(page => new DynamicUserComponentPropertySection( + page, compName, `${findResult.file.getModTime()}`)); + } } } + // for (const model of finder.getUserComponentsModels()) { + + // for (const comp of model.model.getComponents()) { + + // result.push(page => new DynamicUserComponentPropertySection( + // page, comp.getName(), `${model.file.getModTime()}`)); + // } + // } + return result; } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts index 7fc8d51fb..3f937e674 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPopertyProvider.ts @@ -34,7 +34,7 @@ namespace phasereditor2d.scene.ui.editor.properties { for (const ext of exts) { - const providers = ext.getSectionProviders(); + const providers = ext.getSectionProviders(this._editor); for (const provider of providers) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPropertySectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPropertySectionExtension.ts index dc63df964..6d97b9f41 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPropertySectionExtension.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/SceneEditorPropertySectionExtension.ts @@ -16,7 +16,7 @@ namespace phasereditor2d.scene.ui.editor.properties { this._sectionProviders = sectionProviders; } - getSectionProviders() { + getSectionProviders(editor?: SceneEditor) { return this._sectionProviders; } From 88bd6b07f51cfe3dd45fa654cb321406d35424bd Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 14:31:13 -0400 Subject: [PATCH 48/72] Fixes bug when command dialog is open and you press the arrow keys in the context of a scene editor. --- .../src/ui/editor/commands/SceneEditorCommands.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index 2fbd7cbfe..198c4d276 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -68,6 +68,12 @@ namespace phasereditor2d.scene.ui.editor.commands { export const CMD_ADD_USER_COMPONENT = "phasereditor2d.scene.ui.editor.commands.AddUserComponent"; export const CMD_BROWSE_USER_COMPONENTS = "phasereditor2d.scene.ui.editor.commands.BrowseUserComponents"; + function isCommandDialogActive() { + + return colibri.Platform.getWorkbench() + .getActiveDialog() instanceof controls.dialogs.CommandDialog + } + function isSceneScope(args: colibri.ui.ide.commands.HandlerArgs) { if (args.activeDialog) { @@ -1400,6 +1406,11 @@ namespace phasereditor2d.scene.ui.editor.commands { return false; } + if (isCommandDialogActive()) { + + return false; + } + if (args.activeEditor.getSelection().length === 0) { return false; From 14b55ea243901a1d3690a3ee58202d65efddaea1 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 22:14:18 -0400 Subject: [PATCH 49/72] Shows prefab instance properties in its own section. --- .../phasereditor2d.scene/src/ScenePlugin.ts | 2 +- .../src/core/json/SceneFinder.ts | 4 +- .../DynamicUserComponentPropertySection.ts | 14 +- .../DynamicUserComponentSectionExtension.ts | 46 ------ .../properties/DynamicUserSectionExtension.ts | 147 ++++++++++++++++++ .../DynamicPrefabInstanceSection.ts | 117 ++++++++++++++ 6 files changed, 279 insertions(+), 51 deletions(-) delete mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts create mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index 604b509ea..94861a73b 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -378,7 +378,7 @@ namespace phasereditor2d.scene { // dynamic component sections - reg.addExtension(new ui.editor.properties.DynamicUserComponentSectionExtension()); + reg.addExtension(new ui.editor.properties.DynamicUserSectionExtension()); // more property sections diff --git a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts index d239b7849..711d8aa25 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts @@ -446,13 +446,13 @@ namespace phasereditor2d.scene.core.json { return this.getPrefabHierarchy2(prefabId, []); } - isPrefabVariant(basePrefabFile: io.FilePath, superPrefanFile: io.FilePath) { + isPrefabVariant(basePrefabFile: io.FilePath, superPrefabFile: io.FilePath) { const basePrefabId = this.getPrefabId(basePrefabFile); const result = this.getPrefabHierarchy(basePrefabId); - if (result.indexOf(superPrefanFile) >= 0) { + if (result.indexOf(superPrefabFile) >= 0) { return true; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts index 30215fe06..7a0f950e9 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts @@ -8,13 +8,23 @@ namespace phasereditor2d.scene.ui.editor.properties { private _componentName: string; - constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { + constructor(page: controls.properties.PropertyPage, componentName: string, hash: string, prefabName = "") { super(page, DynamicUserComponentPropertySection.computeId(componentName, hash), - `${componentName} (user component)`); + DynamicUserComponentPropertySection.computeName(componentName, prefabName)); this._componentName = componentName; } + + private static computeName(componentName: string, prefabName: string): string { + + if (prefabName) { + + return `${componentName} ← ${prefabName}`; + } + + return componentName; + } private static computeId(compName: string, hash: string) { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts deleted file mode 100644 index 97047a16e..000000000 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSectionExtension.ts +++ /dev/null @@ -1,46 +0,0 @@ -/// -namespace phasereditor2d.scene.ui.editor.properties { - - export class DynamicUserComponentSectionExtension extends SceneEditorPropertySectionExtension { - - getSectionProviders(editor: SceneEditor): GetPropertySection[] { - - const compNames = editor.getSelectedGameObjects() - .flatMap(obj => obj.getEditorSupport() - .getUserComponentsComponent() - .getUserComponentNodes()) - .map(compNode => compNode.getComponentName()) - - const used = new Set(); - - const result: GetPropertySection[] = []; - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - for(const compName of compNames) { - - if (!used.has(compName)) { - - const findResult = finder.getUserComponentByName(compName); - - if (findResult) { - - result.push(page => new DynamicUserComponentPropertySection( - page, compName, `${findResult.file.getModTime()}`)); - } - } - } - - // for (const model of finder.getUserComponentsModels()) { - - // for (const comp of model.model.getComponents()) { - - // result.push(page => new DynamicUserComponentPropertySection( - // page, comp.getName(), `${model.file.getModTime()}`)); - // } - // } - - return result; - } - } -} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts new file mode 100644 index 000000000..7cd854c58 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts @@ -0,0 +1,147 @@ +/// +namespace phasereditor2d.scene.ui.editor.properties { + + import io = colibri.core.io; + + export class DynamicUserSectionExtension extends SceneEditorPropertySectionExtension { + + getSectionProviders(editor: SceneEditor): GetPropertySection[] { + + const result: GetPropertySection[] = []; + + const visitedPrefabs = new Set(); + const visitedComps = new Set(); + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + // add local user components + + for (const obj of editor.getSelectedGameObjects()) { + + const objES = obj.getEditorSupport(); + + const localComps = objES.getUserComponentsComponent() + .getLocalUserComponents(); + + for (const compInfo of localComps) { + + const compName = compInfo.component.getName(); + + visitedComps.add(compName); + + result.push(page => new DynamicUserComponentPropertySection( + page, compName, `${compInfo.file.getModTime()}`)); + } + } + + + for (const obj of editor.getSelectedGameObjects()) { + + const objES = obj.getEditorSupport(); + + if (!objES.isPrefabInstance()) { + + continue; + } + + const prefabFile = objES.getPrefabFile(); + + if (visitedPrefabs.has(prefabFile)) { + + continue; + } + + visitedPrefabs.add(prefabFile); + + const prefabUserProps = objES.getComponent(sceneobjects.PrefabUserPropertyComponent) as sceneobjects.PrefabUserPropertyComponent; + const prefabInfoList = prefabUserProps.getPropertiesByPrefab(); + + // add all properties from prefabs + + for (const prefabInfo of prefabInfoList) { + + // add section for the current prefab info + + result.push(page => new sceneobjects.DynamicPrefabInstanceSection( + page, prefabInfo.prefabFile, prefabInfo.properties)); + + // add all user component properties defined in the current prefab + + const userComps = objES.getUserComponentsComponent(); + + const compNames = userComps + .getPrefabUserComponents() + .filter(i => i.prefabFile === prefabInfo.prefabFile) + .flatMap(i => i.components) + .map(c => c.getName()) + .filter(name => !visitedComps.has(name)); + + for (const compName of compNames) { + + visitedComps.add(compName); + + const findResult = finder.getUserComponentByName(compName); + + if (findResult) { + + const prefabName = prefabInfo.prefabFile.getNameWithoutExtension(); + + result.push(page => new DynamicUserComponentPropertySection( + page, compName, `${findResult.file.getModTime()}`, prefabName)); + } + } + } + } + + + // this.addUserComponentSections(editor, result); + + // this.addPrefabSections(editor, result); + + return result; + } + + private addPrefabSections(editor: SceneEditor, result: GetPropertySection[]) { + + for (const obj of editor.getSelectedGameObjects()) { + + const objES = obj.getEditorSupport(); + const prefabUserProps = objES.getComponent(sceneobjects.PrefabUserPropertyComponent) as sceneobjects.PrefabUserPropertyComponent; + const infoList = prefabUserProps.getPropertiesByPrefab(); + + for (const info of infoList) { + + result.push(page => new sceneobjects.DynamicPrefabInstanceSection( + page, info.prefabFile, info.properties)); + } + } + } + + private addUserComponentSections(editor: SceneEditor, result: GetPropertySection[]) { + + const compNames = editor.getSelectedGameObjects() + .flatMap(obj => obj.getEditorSupport() + .getUserComponentsComponent() + .getUserComponentNodes()) + .map(compNode => compNode.getComponentName()); + + const used = new Set(); + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + for (const compName of compNames) { + + if (!used.has(compName)) { + + const findResult = finder.getUserComponentByName(compName); + + if (findResult) { + + result.push(page => new DynamicUserComponentPropertySection( + page, compName, `${findResult.file.getModTime()}`)); + } + } + } + } + } +} \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts new file mode 100644 index 000000000..fa9ee1087 --- /dev/null +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts @@ -0,0 +1,117 @@ +namespace phasereditor2d.scene.ui.sceneobjects { + + import controls = colibri.ui.controls; + import io = colibri.core.io; + + export class DynamicPrefabInstanceSection extends SceneGameObjectSection { + + private _prefabFile: io.FilePath; + private _properties: UserProperty[]; + + constructor( + page: controls.properties.PropertyPage, + prefabFile: io.FilePath, + properties: UserProperty[]) { + super(page, + DynamicPrefabInstanceSection.computeId(prefabFile), + prefabFile.getNameWithoutExtension(), + false, true); + + this._prefabFile = prefabFile; + this._properties = properties; + } + + private static computeId(prefabFile: io.FilePath) { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + const id = finder.getPrefabId(prefabFile); + const hash = prefabFile.getModTime(); + + return `phasereditor2d.scene.ui.sceneobjects.DynamicPrefabInstanceSection_${id}_${hash}`; + } + + getSectionHelpPath() { + + return "scene-editor/prefab-user-properties.html#user-properties-in-a-prefab-instance"; + } + + createMenu(menu: controls.Menu) { + + menu.addCommand(editor.commands.CMD_OPEN_PREFAB); + + const prefabName = this._prefabFile.getNameWithoutExtension(); + + menu.addAction({ + text: `Select All ${prefabName}`, + callback: () => { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const sel = []; + + this.getEditor().getScene().visitAll(obj2 => { + + if (GameObjectEditorSupport.hasEditorSupport(obj2)) { + + const editorSupport = GameObjectEditorSupport.getEditorSupport(obj2); + + if (editorSupport.isPrefabInstance()) { + + const prefabFiles = finder.getPrefabHierarchy(editorSupport.getPrefabId()); + + if (prefabFiles.indexOf(this._prefabFile) >= 0) { + + sel.push(obj2); + } + } + } + }); + + this.getEditor().setSelection(sel); + } + }); + + menu.addSeparator(); + + super.createMenu(menu); + } + + createForm(parent: HTMLDivElement) { + + const comp = this.createGridElement(parent); + comp.style.gridTemplateColumns = "auto auto 1fr"; + + for (const prop of this._properties) { + + prop.getType().createInspectorPropertyEditor(this, comp, prop, true); + } + } + + canEdit(obj: sceneobjects.ISceneGameObject, n: number): boolean { + + if (sceneobjects.isGameObject(obj)) { + + const objES = obj.getEditorSupport(); + + if (objES.isPrefabInstance()) { + + const objPrefabFile = objES.getPrefabFile(); + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + if (finder.isPrefabVariant(objPrefabFile, this._prefabFile)) { + + return true; + } + } + } + + return false; + } + + canEditNumber(n: number): boolean { + + return n > 0; + } + } +} \ No newline at end of file From 7ea133bf7e958bd8fc726bd7887e9c529548e61e Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 22:50:30 -0400 Subject: [PATCH 50/72] improves section title of prefab instance properties section. --- .../ui/controls/properties/PropertyPage.ts | 7 +++ .../ui/controls/properties/PropertySection.ts | 7 +++ .../properties/PropertySectionPane.ts | 21 +++++--- .../DynamicUserComponentPropertySection.ts | 47 +++++++++++++---- .../properties/DynamicUserSectionExtension.ts | 52 +------------------ 5 files changed, 66 insertions(+), 68 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts index 49c6b2a14..47b98b1d3 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts @@ -51,7 +51,9 @@ namespace colibri.ui.controls.properties { const sectionIdList = list.map(section => section.getId()); for (const pane of this._sectionPanes) { + const index = sectionIdList.indexOf(pane.getSection().getId()); + pane.getElement().style.order = index.toString(); } @@ -142,6 +144,11 @@ namespace colibri.ui.controls.properties { pane.createSection(); section.updateWithSelection(); + if (section.isDynamicTitle()) { + + pane.updateTitle(); + } + } else { pane.getElement().style.display = "none"; diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts index e33bc015e..f425aaaec 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts @@ -86,13 +86,20 @@ namespace colibri.ui.controls.properties { } getId() { + return this._id; } getTitle() { + return this._title; } + isDynamicTitle() { + + return false; + } + create(parent: HTMLDivElement): void { this.createForm(parent); } diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts index ade9677d7..66e292028 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts @@ -8,6 +8,7 @@ namespace colibri.ui.controls.properties { private _page: PropertyPage; private _menuIcon: IconControl; private _expandIconControl: IconControl; + private _titleLabel: HTMLLabelElement; constructor(page: PropertyPage, section: PropertySection) { super(); @@ -40,9 +41,9 @@ namespace colibri.ui.controls.properties { this._titleArea.appendChild(this._expandIconControl.getCanvas()); - const label = document.createElement("label"); - label.innerText = this._section.getTitle(); - this._titleArea.appendChild(label); + this._titleLabel = document.createElement("label"); + this.updateTitle() + this._titleArea.appendChild(this._titleLabel); this._menuIcon = new IconControl(ColibriPlugin.getInstance().getIcon(ICON_SMALL_MENU)); this._menuIcon.getCanvas().classList.add("IconButton"); @@ -103,6 +104,7 @@ namespace colibri.ui.controls.properties { isExpanded() { + return this._expandIconControl.getCanvas().classList.contains("expanded"); } @@ -128,6 +130,14 @@ namespace colibri.ui.controls.properties { this.setCollapsedStateInStorage(!this.isExpanded()); } + updateTitle() { + + if (this._titleLabel) { + + this._titleLabel.innerText = this._section.getTitle(); + } + } + private updateExpandIcon() { const icon = this.isExpanded() ? colibri.ICON_CONTROL_SECTION_COLLAPSE : colibri.ICON_CONTROL_SECTION_EXPAND; @@ -138,11 +148,8 @@ namespace colibri.ui.controls.properties { } getSection() { - return this._section; - } - getFormArea() { - return this._formArea; + return this._section; } } } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts index 7a0f950e9..cacb31ed6 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts @@ -8,27 +8,54 @@ namespace phasereditor2d.scene.ui.editor.properties { private _componentName: string; - constructor(page: controls.properties.PropertyPage, componentName: string, hash: string, prefabName = "") { + constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, DynamicUserComponentPropertySection.computeId(componentName, hash), - DynamicUserComponentPropertySection.computeName(componentName, prefabName)); + componentName); this._componentName = componentName; } - - private static computeName(componentName: string, prefabName: string): string { - if (prefabName) { + private static computeId(compName: string, hash: string) { - return `${componentName} ← ${prefabName}`; - } + return `phasereditor2d.scene.ui.editor.properties.DynamicPropertySection_${compName}_${hash}`; + } + + isDynamicTitle(): boolean { - return componentName; + return true; } - private static computeId(compName: string, hash: string) { + getTitle(): string { - return `phasereditor2d.scene.ui.editor.properties.DynamicPropertySection_${compName}_${hash}`; + const prefabNames = this.getSelection() + .flatMap((obj: sceneobjects.ISceneGameObject) => obj.getEditorSupport() + .getUserComponentsComponent() + .getPrefabUserComponents()) + .filter(i => i.components.find(c => c.getName() === this._componentName)) + .map(i => i.prefabFile.getNameWithoutExtension()); + + const distinctPrefabNames: string[] = []; + + if (prefabNames.length > 0) { + + const used = new Set(); + + for(const prefabName of prefabNames) { + + if (used.has(prefabName)) { + + continue; + } + + used.add(prefabName); + distinctPrefabNames.push(prefabName); + } + + return `${this._componentName} ← ${distinctPrefabNames.join(" | ")}`; + } + + return this._componentName; } createMenu(menu: controls.Menu): void { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts index 7cd854c58..274d4c423 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts @@ -84,64 +84,14 @@ namespace phasereditor2d.scene.ui.editor.properties { if (findResult) { - const prefabName = prefabInfo.prefabFile.getNameWithoutExtension(); - result.push(page => new DynamicUserComponentPropertySection( - page, compName, `${findResult.file.getModTime()}`, prefabName)); + page, compName, `${findResult.file.getModTime()}`)); } } } } - - // this.addUserComponentSections(editor, result); - - // this.addPrefabSections(editor, result); - return result; } - - private addPrefabSections(editor: SceneEditor, result: GetPropertySection[]) { - - for (const obj of editor.getSelectedGameObjects()) { - - const objES = obj.getEditorSupport(); - const prefabUserProps = objES.getComponent(sceneobjects.PrefabUserPropertyComponent) as sceneobjects.PrefabUserPropertyComponent; - const infoList = prefabUserProps.getPropertiesByPrefab(); - - for (const info of infoList) { - - result.push(page => new sceneobjects.DynamicPrefabInstanceSection( - page, info.prefabFile, info.properties)); - } - } - } - - private addUserComponentSections(editor: SceneEditor, result: GetPropertySection[]) { - - const compNames = editor.getSelectedGameObjects() - .flatMap(obj => obj.getEditorSupport() - .getUserComponentsComponent() - .getUserComponentNodes()) - .map(compNode => compNode.getComponentName()); - - const used = new Set(); - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - for (const compName of compNames) { - - if (!used.has(compName)) { - - const findResult = finder.getUserComponentByName(compName); - - if (findResult) { - - result.push(page => new DynamicUserComponentPropertySection( - page, compName, `${findResult.file.getModTime()}`)); - } - } - } - } } } \ No newline at end of file From 630517e7542cc482779ff72470e18206d40de1f8 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 21 Jun 2023 23:13:55 -0400 Subject: [PATCH 51/72] Fixes nesetd prefab instance property section generation. --- .../properties/DynamicPrefabInstanceSection.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts index fa9ee1087..23ba7c19c 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts @@ -98,10 +98,24 @@ namespace phasereditor2d.scene.ui.sceneobjects { const objPrefabFile = objES.getPrefabFile(); const finder = ScenePlugin.getInstance().getSceneFinder(); + + if (objES.isNestedPrefabInstance()) { - if (finder.isPrefabVariant(objPrefabFile, this._prefabFile)) { + const objPrefabId = finder.getFirstNonNestedPrefabId(objES.getPrefabId()); - return true; + if (objPrefabId) { + + const sectionPrefabId = finder.getPrefabId(this._prefabFile); + + return objPrefabId === sectionPrefabId; + } + + } else { + + if (finder.isPrefabVariant(objPrefabFile, this._prefabFile)) { + + return true; + } } } } From b0b4d859d509087b8a83d26edc6829eb4cb78d1d Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 09:37:36 -0400 Subject: [PATCH 52/72] Fixes local user component property editor lock icon. --- ...pertySection.ts => DynamicUserComponentSection.ts} | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) rename source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/{DynamicUserComponentPropertySection.ts => DynamicUserComponentSection.ts} (95%) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts similarity index 95% rename from source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts rename to source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index cacb31ed6..af65a1b4a 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentPropertySection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -4,13 +4,13 @@ namespace phasereditor2d.scene.ui.editor.properties { import controls = colibri.ui.controls; import io = colibri.core.io; - export class DynamicUserComponentPropertySection extends sceneobjects.SceneGameObjectSection { + export class DynamicUserComponentSection extends sceneobjects.SceneGameObjectSection { private _componentName: string; constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, - DynamicUserComponentPropertySection.computeId(componentName, hash), + DynamicUserComponentSection.computeId(componentName, hash), componentName); this._componentName = componentName; @@ -41,7 +41,7 @@ namespace phasereditor2d.scene.ui.editor.properties { const used = new Set(); - for(const prefabName of prefabNames) { + for (const prefabName of prefabNames) { if (used.has(prefabName)) { @@ -283,7 +283,10 @@ namespace phasereditor2d.scene.ui.editor.properties { if (props.length > 0) { const atLeastOnePrefab = this.getSelection() - .filter(obj => obj.getEditorSupport().isPrefabInstance()) + .map(obj => obj.getEditorSupport()) + .filter(objES => objES.isPrefabInstance() + && !objES.getUserComponentsComponent() + .hasLocalUserComponent(this._componentName)) .length > 0; for (const prop of props) { From 61988334732dd44de5d05463adaeda26f324d7e5 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 09:38:03 -0400 Subject: [PATCH 53/72] Rename. --- .../src/ui/editor/properties/DynamicUserSectionExtension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts index 274d4c423..3353b6b64 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserSectionExtension.ts @@ -29,7 +29,7 @@ namespace phasereditor2d.scene.ui.editor.properties { visitedComps.add(compName); - result.push(page => new DynamicUserComponentPropertySection( + result.push(page => new DynamicUserComponentSection( page, compName, `${compInfo.file.getModTime()}`)); } } @@ -84,7 +84,7 @@ namespace phasereditor2d.scene.ui.editor.properties { if (findResult) { - result.push(page => new DynamicUserComponentPropertySection( + result.push(page => new DynamicUserComponentSection( page, compName, `${findResult.file.getModTime()}`)); } } From 7c93779ef15678aa470cc9c8876a9d062b453fb8 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 09:46:46 -0400 Subject: [PATCH 54/72] Fixes section menu in local user components. --- .../colibri/src/ui/controls/properties/PropertyPage.ts | 2 ++ .../src/ui/editor/properties/DynamicUserComponentSection.ts | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts index 47b98b1d3..390924778 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts @@ -28,6 +28,8 @@ namespace colibri.ui.controls.properties { private build() { + console.log("build()", Date.now()); + if (this._sectionProvider) { const list: Array> = []; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index af65a1b4a..12edccdc9 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -116,13 +116,13 @@ namespace phasereditor2d.scene.ui.editor.properties { menu.addAction({ text: `Reveal In ${prefabFile.getNameWithoutExtension()} File`, - callback: () => this.openPrefabLinkInSceneEditor(prefabFile) + callback: () => this.openPrefabDefInSceneEditor(prefabFile) }); } } const allLocalNodes = this.getSelection() - .map(obj => obj.getEditorSupport() + .filter(obj => obj.getEditorSupport() .getUserComponentsComponent() .hasLocalUserComponent(this._componentName)) .length === this.getSelection().length; @@ -192,7 +192,7 @@ namespace phasereditor2d.scene.ui.editor.properties { editor.getUndoManager().add(new ui.editor.undo.SimpleSceneSnapshotOperation(editor, action)); } - private openPrefabLinkInSceneEditor(prefabFile: io.FilePath) { + private openPrefabDefInSceneEditor(prefabFile: io.FilePath) { const prefabEditor = colibri.Platform.getWorkbench().openEditor(prefabFile); From cb899b054bef10bc1b42a81c0ac361f7cf64bd45 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 10:10:17 -0400 Subject: [PATCH 55/72] Shows an icon in the dynamic sections. --- .../ui/controls/properties/PropertySection.ts | 18 ++++++++++++++++-- .../controls/properties/PropertySectionPane.ts | 10 ++++++++++ .../editor/plugins/colibri/styles/controls.css | 8 ++++++++ .../properties/DynamicUserComponentSection.ts | 2 +- .../properties/DynamicPrefabInstanceSection.ts | 2 +- 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts index f425aaaec..b3d4bdcc6 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts @@ -11,8 +11,16 @@ namespace colibri.ui.controls.properties { private _updaters: Updater[]; private _fillSpace: boolean; private _collapsedByDefault: boolean; + private _icon: controls.IImage; + + constructor( + page: PropertyPage, + id: string, + title: string, + fillSpace = false, + collapsedByDefault = false, + icon?: controls.IImage) { - constructor(page: PropertyPage, id: string, title: string, fillSpace = false, collapsedByDefault = false, tabSectionByDefault?: string) { super(); this._page = page; @@ -20,12 +28,13 @@ namespace colibri.ui.controls.properties { this._title = title; this._fillSpace = fillSpace; this._collapsedByDefault = collapsedByDefault; + this._icon = icon; this._updaters = []; const localTabSection = localStorage.getItem(this.localStorageKey("tabSection")); } - abstract createForm(parent: HTMLDivElement); + abstract createForm(parent: HTMLDivElement): void; abstract canEdit(obj: any, n: number): boolean; @@ -100,6 +109,11 @@ namespace colibri.ui.controls.properties { return false; } + getIcon() { + + return this._icon; + } + create(parent: HTMLDivElement): void { this.createForm(parent); } diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts index 66e292028..0496e911b 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts @@ -41,6 +41,16 @@ namespace colibri.ui.controls.properties { this._titleArea.appendChild(this._expandIconControl.getCanvas()); + const icon = this._section.getIcon(); + + if (icon) { + + const iconControl = new IconControl(icon); + iconControl.getCanvas().classList.add("PropertySectionIcon"); + this._titleArea.appendChild(iconControl.getCanvas()); + this._titleArea.classList.add("PropertyTitleAreaWithIcon"); + } + this._titleLabel = document.createElement("label"); this.updateTitle() this._titleArea.appendChild(this._titleLabel); diff --git a/source/editor/plugins/colibri/styles/controls.css b/source/editor/plugins/colibri/styles/controls.css index 212403c83..49b37d97a 100644 --- a/source/editor/plugins/colibri/styles/controls.css +++ b/source/editor/plugins/colibri/styles/controls.css @@ -328,6 +328,14 @@ padding: 5px; } + .PropertyTitleAreaWithIcon { + grid-template-columns: 20px 20px 1fr auto !important; + } + + .PropertyTitleArea .PropertySectionIcon { + margin-right: 5px; + } + .PropertyTitleArea .IconControlCanvas { align-self: center; justify-self: center; diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index 12edccdc9..9b07b33e8 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -11,7 +11,7 @@ namespace phasereditor2d.scene.ui.editor.properties { constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, DynamicUserComponentSection.computeId(componentName, hash), - componentName); + componentName, false, true, ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT)); this._componentName = componentName; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts index 23ba7c19c..095fa7c17 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts @@ -15,7 +15,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { super(page, DynamicPrefabInstanceSection.computeId(prefabFile), prefabFile.getNameWithoutExtension(), - false, true); + false, true, ScenePlugin.getInstance().getIcon(ICON_GROUP)); this._prefabFile = prefabFile; this._properties = properties; From 1d571de2568bb399698fbcd673f1f776480d3e7b Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 10:14:41 -0400 Subject: [PATCH 56/72] Removes old Prefab Instanse Property Section. --- .../phasereditor2d.scene/src/ScenePlugin.ts | 3 +- .../PrefabInstanceUserPropertySection.ts | 192 ------------------ 2 files changed, 1 insertion(+), 194 deletions(-) delete mode 100644 source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/PrefabInstanceUserPropertySection.ts diff --git a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts index 94861a73b..14f912bcb 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ScenePlugin.ts @@ -372,8 +372,7 @@ namespace phasereditor2d.scene { reg.addExtension(new ui.editor.properties.SceneEditorPropertySectionExtension( page => new ui.sceneobjects.GameObjectVariableSection(page), page => new ui.sceneobjects.PrefabObjectVariableSection(page), - page => new ui.sceneobjects.NestedPrefabObjectVariableSection(page), - page => new ui.sceneobjects.PrefabInstanceSection(page) + page => new ui.sceneobjects.NestedPrefabObjectVariableSection(page) )); // dynamic component sections diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/PrefabInstanceUserPropertySection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/PrefabInstanceUserPropertySection.ts deleted file mode 100644 index 6712d7ba8..000000000 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/PrefabInstanceUserPropertySection.ts +++ /dev/null @@ -1,192 +0,0 @@ -namespace phasereditor2d.scene.ui.sceneobjects { - - import controls = colibri.ui.controls; - - export class PrefabInstanceSection extends SceneGameObjectSection { - - private _propArea: HTMLDivElement; - - constructor(page: controls.properties.PropertyPage) { - super(page, - "phasereditor2d.scene.ui.sceneobjects.PrefabInstanceUserPropertySection", "Prefab Instance"); - } - - getSectionHelpPath() { - - return "scene-editor/prefab-user-properties.html#user-properties-in-a-prefab-instance"; - } - - createMenu(menu: controls.Menu) { - - menu.addCommand(editor.commands.CMD_OPEN_PREFAB); - - menu.addSeparator(); - - super.createMenu(menu); - } - - createForm(parent: HTMLDivElement) { - - const comp = this.createGridElement(parent); - comp.style.gridTemplateColumns = "1fr"; - - this._propArea = this.createGridElement(comp); - this._propArea.style.gridTemplateColumns = "auto auto 1fr"; - - comp.appendChild(this._propArea); - - this.addUpdater(() => { - - this._propArea.innerHTML = ""; - - const obj = this.getSelectionFirstElement() as ISceneGameObject; - - // properties of non-nested prefabs - - const userPropsComponent = GameObjectEditorSupport - .getObjectComponent(obj, PrefabUserPropertyComponent) as PrefabUserPropertyComponent; - - const propsByPrefabList = userPropsComponent.getPropertiesByPrefab(); - - for (const propsByPrefab of propsByPrefabList) { - - const prefabFile = propsByPrefab.prefabFile; - const prefabName = prefabFile.getNameWithoutExtension(); - - const headerDiv = this.createPrefabLink(prefabFile); - - this.createMenuIcon(headerDiv, () => { - - const menu = new controls.Menu(); - - menu.addAction({ - text: `Select All ${prefabName}`, - callback: () => { - - const finder = ScenePlugin.getInstance().getSceneFinder(); - - const sel = []; - - this.getEditor().getScene().visitAll(obj2 => { - - if (GameObjectEditorSupport.hasEditorSupport(obj2)) { - - const editorSupport = GameObjectEditorSupport.getEditorSupport(obj2); - - if (editorSupport.isPrefabInstance()) { - - const prefabFiles = finder.getPrefabHierarchy(editorSupport.getPrefabId()); - - if (prefabFiles.indexOf(prefabFile) >= 0) { - - sel.push(obj2); - } - } - } - }); - - this.getEditor().setSelection(sel); - } - }); - - menu.addAction({ - text: `Open ${prefabName} File`, - callback: () => colibri.Platform.getWorkbench().openEditor(prefabFile) - }) - - return menu; - }); - - for (const prop of propsByPrefab.properties) { - - prop.getType().createInspectorPropertyEditor(this, this._propArea, prop, true); - } - } - - // link to nested prefab - - const objES = obj.getEditorSupport(); - - if (objES.isNestedPrefabInstance()) { - - const file = objES.getPrefabFile(); - - this.createPrefabLink(file, `${file.getNameWithoutExtension()} (nested in)`); - } - }); - } - - private createPrefabLink(file: colibri.core.io.FilePath, btnText?:string) { - - const headerDiv = document.createElement("div"); - headerDiv.classList.add("PrefabLink"); - headerDiv.style.gridColumn = "1 / span 3"; - this._propArea.appendChild(headerDiv); - - const prefabBtn = document.createElement("a"); - prefabBtn.href = "#"; - prefabBtn.innerHTML = btnText ?? file.getNameWithoutExtension(); - headerDiv.appendChild(prefabBtn); - - prefabBtn.addEventListener("click", () => colibri.Platform.getWorkbench().openEditor(file)); - - return headerDiv; - } - - canEdit(obj: any, n: number): boolean { - - return true; - } - - canEditNumber(n: number): boolean { - - if (n === 0) { - - return false; - } - - const obj = this.getSelectionFirstElement(); - - if (GameObjectEditorSupport.hasEditorSupport(obj)) { - - const support = GameObjectEditorSupport.getEditorSupport(obj); - - if (support.isPrefabInstance()) { - - const prefabFile = support.getPrefabFile(); - - for (const obj2 of this.getSelection()) { - - if (GameObjectEditorSupport.hasEditorSupport(obj2)) { - - const support2 = GameObjectEditorSupport.getEditorSupport(obj2); - - if (support2.isPrefabInstance()) { - - const prefabFile2 = support2.getPrefabFile(); - - if (prefabFile !== prefabFile2) { - - return false; - } - - } else { - - return false; - } - - } else { - - return false; - } - } - - return true; - } - } - - - return false; - } - } -} \ No newline at end of file From a5af23bd6491551a71fa88d4018ed558c9546364 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 10:26:14 -0400 Subject: [PATCH 57/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 26af27558..0d9fb1dd9 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -18,6 +18,7 @@ - Add User Component - Browse User Components * Removes user component nodes from the Outline view. +* Removes the Prefab Instance section, now it shows the prefab instance user properties as common sections. ## v3.61.0 - May 18, 2023 From fbe57a4b8918cf3c7f7c387cf0241bd7edbfc2a1 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 10:30:54 -0400 Subject: [PATCH 58/72] Updates changelog. --- CHANGELOG.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 0d9fb1dd9..bf671214a 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -13,12 +13,12 @@ * Shows Keyboard.Key and Object List objects in the Object Variable user property's dialog.. * Adds the new KeyCode User Property. * Fixes hit area serialization. -* Removes the User Components section and show user components properties as individual sections: +* Removes the User Components section and shows user components properties as individual sections: * Renames the Scripts context menu to Scripting and include: - Add User Component - Browse User Components * Removes user component nodes from the Outline view. -* Removes the Prefab Instance section, now it shows the prefab instance user properties as common sections. +* Removes the Prefab Instance section, shows the prefab instance user properties as individual sections. ## v3.61.0 - May 18, 2023 From b8a5a0215249377488e082c0e35c20e17efb09cf Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 11:35:17 -0400 Subject: [PATCH 59/72] Optimizes dynamic section pane management. --- .../colibri/src/ui/controls/Control.ts | 17 +++++++++++ .../ui/controls/properties/PropertyPage.ts | 29 ++++++++++++++++--- .../ui/controls/properties/PropertySection.ts | 13 ++++++++- .../properties/PropertySectionPane.ts | 7 +++++ .../properties/DynamicUserComponentSection.ts | 4 ++- .../DynamicPrefabInstanceSection.ts | 12 +++++++- 6 files changed, 75 insertions(+), 7 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/controls/Control.ts b/source/editor/plugins/colibri/src/ui/controls/Control.ts index 2586ba1b8..9d676fe13 100644 --- a/source/editor/plugins/colibri/src/ui/controls/Control.ts +++ b/source/editor/plugins/colibri/src/ui/controls/Control.ts @@ -212,16 +212,33 @@ namespace colibri.ui.controls { } add(control: Control): void { + control._container = this; + this._children.push(control); + this._element.appendChild(control.getElement()); + control.onControlAdded(); } + remove(control: Control) { + + control.getElement().remove(); + + this._children = this._children.filter(c => c !== control); + + control.onControlRemoved(); + } + protected onControlAdded() { // nothing } + protected onControlRemoved() { + // nothing + } + getChildren() { return this._children; } diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts index 390924778..4bdf7b37b 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertyPage.ts @@ -28,8 +28,6 @@ namespace colibri.ui.controls.properties { private build() { - console.log("build()", Date.now()); - if (this._sectionProvider) { const list: Array> = []; @@ -42,6 +40,12 @@ namespace colibri.ui.controls.properties { const pane = new PropertySectionPane(this, section); + if (section.getTypeHash()) { + + this.removePanesWithSameTypeHash(section.getTypeHash()); + } + + console.log("PropertyPage: create pane for", section.getTitle(), section.getId()); this.add(pane); this._sectionPaneMap.set(section.getId(), pane); @@ -64,12 +68,29 @@ namespace colibri.ui.controls.properties { } else { for (const pane of this._sectionPanes) { - + pane.getElement().style.display = "none"; } } } + private removePanesWithSameTypeHash(typeHash: string) { + + for (const pane of this._sectionPanes) { + + const section = pane.getSection(); + + if (section.getTypeHash() === typeHash) { + + console.log("PropertyPage: remove dynamic pane", section.getTitle(), section.getId()); + this.remove(pane); + } + } + + this._sectionPanes = this._sectionPanes + .filter(pane => pane.getSection().getTypeHash() !== typeHash); + } + public updateWithSelection(): void { if (!this._sectionProvider) { @@ -220,7 +241,7 @@ namespace colibri.ui.controls.properties { } getSectionProvider() { - + return this._sectionProvider; } } diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts index b3d4bdcc6..f68f49bd8 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySection.ts @@ -12,6 +12,7 @@ namespace colibri.ui.controls.properties { private _fillSpace: boolean; private _collapsedByDefault: boolean; private _icon: controls.IImage; + private _typeHash: string; constructor( page: PropertyPage, @@ -19,7 +20,8 @@ namespace colibri.ui.controls.properties { title: string, fillSpace = false, collapsedByDefault = false, - icon?: controls.IImage) { + icon?: controls.IImage, + typeHash?: string) { super(); @@ -29,6 +31,8 @@ namespace colibri.ui.controls.properties { this._fillSpace = fillSpace; this._collapsedByDefault = collapsedByDefault; this._icon = icon; + this._typeHash = typeHash; + this._updaters = []; const localTabSection = localStorage.getItem(this.localStorageKey("tabSection")); @@ -68,6 +72,7 @@ namespace colibri.ui.controls.properties { } addUpdater(updater: Updater) { + this._updaters.push(updater); } @@ -81,6 +86,7 @@ namespace colibri.ui.controls.properties { } getPage() { + return this._page; } @@ -114,6 +120,11 @@ namespace colibri.ui.controls.properties { return this._icon; } + getTypeHash() { + + return this._typeHash; + } + create(parent: HTMLDivElement): void { this.createForm(parent); } diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts index 0496e911b..73a5a8753 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts @@ -18,6 +18,13 @@ namespace colibri.ui.controls.properties { this._section = section; this.addClass("PropertySectionPane"); + + const hashType = section.getTypeHash(); + + if (hashType) { + + this.getElement().setAttribute("type-hash", section.getTypeHash()); + } } createSection() { diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index 9b07b33e8..e3f908904 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -11,7 +11,9 @@ namespace phasereditor2d.scene.ui.editor.properties { constructor(page: controls.properties.PropertyPage, componentName: string, hash: string) { super(page, DynamicUserComponentSection.computeId(componentName, hash), - componentName, false, true, ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT)); + componentName, false, true, + ScenePlugin.getInstance().getIcon(ICON_USER_COMPONENT), + `DynamicUserComponentSection_${componentName}}`); this._componentName = componentName; } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts index 095fa7c17..656048334 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/object/properties/DynamicPrefabInstanceSection.ts @@ -15,12 +15,22 @@ namespace phasereditor2d.scene.ui.sceneobjects { super(page, DynamicPrefabInstanceSection.computeId(prefabFile), prefabFile.getNameWithoutExtension(), - false, true, ScenePlugin.getInstance().getIcon(ICON_GROUP)); + false, true, ScenePlugin.getInstance().getIcon(ICON_GROUP), + DynamicPrefabInstanceSection.computeTypeHash(prefabFile)); this._prefabFile = prefabFile; this._properties = properties; } + private static computeTypeHash(prefabFile: io.FilePath): string { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const prefabId = finder.getPrefabId(prefabFile); + + return `DynamicPrefabInstanceSection_${prefabFile.getNameWithoutExtension()}_${prefabId}` + } + private static computeId(prefabFile: io.FilePath) { const finder = ScenePlugin.getInstance().getSceneFinder(); From a997aeb2b209251b7ab4b4dbc4355737df75894e Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 12:03:29 -0400 Subject: [PATCH 60/72] Improves section title rendering of dynamic user components. --- .../src/ui/controls/properties/PropertySectionPane.ts | 5 +++-- .../src/ui/editor/properties/DynamicUserComponentSection.ts | 2 +- .../plugins/phasereditor2d.scene/styles/SceneEditor.css | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts index 73a5a8753..89c75cb44 100644 --- a/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts +++ b/source/editor/plugins/colibri/src/ui/controls/properties/PropertySectionPane.ts @@ -59,7 +59,8 @@ namespace colibri.ui.controls.properties { } this._titleLabel = document.createElement("label"); - this.updateTitle() + this._titleLabel.classList.add("TitleLabel"); + this.updateTitle(); this._titleArea.appendChild(this._titleLabel); this._menuIcon = new IconControl(ColibriPlugin.getInstance().getIcon(ICON_SMALL_MENU)); @@ -151,7 +152,7 @@ namespace colibri.ui.controls.properties { if (this._titleLabel) { - this._titleLabel.innerText = this._section.getTitle(); + this._titleLabel.innerHTML = this._section.getTitle(); } } diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index e3f908904..125860ebe 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -54,7 +54,7 @@ namespace phasereditor2d.scene.ui.editor.properties { distinctPrefabNames.push(prefabName); } - return `${this._componentName} ← ${distinctPrefabNames.join(" | ")}`; + return `${this._componentName} ← ${distinctPrefabNames.join(" & ")}`; } return this._componentName; diff --git a/source/editor/plugins/phasereditor2d.scene/styles/SceneEditor.css b/source/editor/plugins/phasereditor2d.scene/styles/SceneEditor.css index b335a5cee..8cd797191 100644 --- a/source/editor/plugins/phasereditor2d.scene/styles/SceneEditor.css +++ b/source/editor/plugins/phasereditor2d.scene/styles/SceneEditor.css @@ -24,6 +24,12 @@ border-radius: 3px; } +#InspectorView .UserComponentTitle_PrefabsPart { + font-size: small; + font-style: italic; + opacity: 0.5; +} + #InspectorView label { min-width: unset; } From 32e9d365723db2b024a0527287e8063265cacd19 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 22:44:26 -0400 Subject: [PATCH 61/72] Fixes: shows the Export field in the user component of a nested prefab. --- .../src/ui/editor/properties/DynamicUserComponentSection.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts index 125860ebe..988ba44bf 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/properties/DynamicUserComponentSection.ts @@ -225,7 +225,6 @@ namespace phasereditor2d.scene.ui.editor.properties { } } - private openComponentEditor() { const finder = ScenePlugin.getInstance().getSceneFinder(); @@ -250,11 +249,14 @@ namespace phasereditor2d.scene.ui.editor.properties { this.addUpdater(() => { + const scene = this.getEditor().getScene(); + const values = this.getSelection().map(obj => { const objES = obj.getEditorSupport(); - if (objES.isScenePrefabObject()) { + if (scene.isPrefabSceneType() + && (objES.isScenePrefabObject() || objES.isNestedPrefabScope())) { if (objES.getUserComponentsComponent() .hasLocalUserComponent(this._componentName)) { From bbaedbf2b9347709a5f93398ce0ffba3a19d5fe9 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 22 Jun 2023 23:04:42 -0400 Subject: [PATCH 62/72] Binds the KeyM to the Add User Component command, and Shift+M to the Browse User Components command. --- CHANGELOG.MD | 1 + .../src/ui/editor/commands/SceneEditorCommands.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index bf671214a..d12144917 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -19,6 +19,7 @@ - Browse User Components * Removes user component nodes from the Outline view. * Removes the Prefab Instance section, shows the prefab instance user properties as individual sections. +* The Replace Texture Frame command responds to the `F` key. ## v3.61.0 - May 18, 2023 diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index 198c4d276..c2a45ed22 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -270,8 +270,8 @@ namespace phasereditor2d.scene.ui.editor.commands { tooltip: "Pick a User Component and add it to the selected objects" }, keys: { - key: "KeyC", - keyLabel: "C" + key: "KeyM", + keyLabel: "M" }, handler: { testFunc: onlyGameObjectsSelected, @@ -393,6 +393,11 @@ namespace phasereditor2d.scene.ui.editor.commands { name: "Browse User Components", tooltip: "Browse all user components in the scene's objects." }, + keys: { + key: "KeyM", + shift: true, + keyLabel: "M" + }, handler: { testFunc: isSceneScope, executeFunc: args => { @@ -1147,7 +1152,7 @@ namespace phasereditor2d.scene.ui.editor.commands { } }, keys: { - key: "KeyM" + key: "KeyF" } }); } From e5006e0d40f29786850818fd4eef62617ce38695 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 23 Jun 2023 11:56:20 -0400 Subject: [PATCH 63/72] Fixes adding a script node to multiple game objects. --- .../phasereditor2d.scene/src/ui/SceneMaker.ts | 9 ++-- .../src/ui/editor/DropManager.ts | 13 +++-- .../undo/CreateObjectWithAssetOperation.ts | 49 ++++++++++++++++++- .../scriptNode/AddScriptDialog.ts | 1 - 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/SceneMaker.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/SceneMaker.ts index 9c9364ff1..68e307866 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/SceneMaker.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/SceneMaker.ts @@ -72,12 +72,13 @@ namespace phasereditor2d.scene.ui { return undefined; } - afterDropObjects(prefabObj: sceneobjects.ISceneGameObject, dropObjects: sceneobjects.ISceneGameObject[]) { + afterDropObjects(prefabObj: sceneobjects.ISceneGameObject, dropObjects: sceneobjects.ISceneGameObject[], alternativeSelection?: sceneobjects.ISceneGameObject[]) { let dropInContainer: sceneobjects.Container; let dropInObj: sceneobjects.ISceneGameObject; - const selection = this._editorScene.getEditor().getSelectedGameObjects(); + const selection = alternativeSelection + || this._editorScene.getEditor().getSelectedGameObjects(); const areDropingScriptNodes = dropObjects.filter(obj => obj instanceof sceneobjects.ScriptNode).length === dropObjects.length; @@ -318,7 +319,9 @@ namespace phasereditor2d.scene.ui { label: "temporal" }); - if (obj.getEditorSupport().isUnlockedProperty(sceneobjects.TransformComponent.x)) { + const objES = obj.getEditorSupport(); + + if (objES.isUnlockedProperty(sceneobjects.TransformComponent.x)) { const { x, y } = this.getCanvasCenterPoint(); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/DropManager.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/DropManager.ts index 25ab1fc0c..f3353f522 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/DropManager.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/DropManager.ts @@ -65,7 +65,9 @@ namespace phasereditor2d.scene.ui.editor { ide.Workbench.getWorkbench().setActivePart(this._editor); } - async createWithDropEvent(dropAssetArray: any[], offsetX: number, offsetY: number) { + async createWithDropEvent( + dropAssetArray: any[], offsetX: number, offsetY: number, + alternativeSelection?: sceneobjects.ISceneGameObject[]) { const scene = this._editor.getScene(); @@ -134,11 +136,12 @@ namespace phasereditor2d.scene.ui.editor { if (sceneMaker.isPrefabFile(data)) { const sprite = await sceneMaker.createPrefabInstanceWithFile(data); + const spriteES = sprite.getEditorSupport(); - if (sprite.getEditorSupport().hasComponent(sceneobjects.TransformComponent)) { + if (spriteES.hasComponent(sceneobjects.TransformComponent)) { - sprite.getEditorSupport().setUnlockedProperty(sceneobjects.TransformComponent.x, true); - sprite.getEditorSupport().setUnlockedProperty(sceneobjects.TransformComponent.y, true); + spriteES.setUnlockedProperty(sceneobjects.TransformComponent.x, true); + spriteES.setUnlockedProperty(sceneobjects.TransformComponent.y, true); (sprite as any as Phaser.GameObjects.Image).setPosition(x, y); } @@ -238,7 +241,7 @@ namespace phasereditor2d.scene.ui.editor { sceneObjectES.setLabel(label); } - scene.getMaker().afterDropObjects(prefabObj, newSprites); + scene.getMaker().afterDropObjects(prefabObj, newSprites, alternativeSelection); sceneobjects.sortGameObjects(newSprites); diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts index 1e493c757..ec9eebbf1 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts @@ -1,6 +1,8 @@ /// namespace phasereditor2d.scene.ui.editor.undo { + import io = colibri.core.io; + export class CreateObjectWithAssetOperation extends SceneSnapshotOperation { private _offsetX: number; @@ -17,9 +19,52 @@ namespace phasereditor2d.scene.ui.editor.undo { protected async performModification() { - const sprites = await this.getEditor().getDropManager().createWithDropEvent(this._data, this._offsetX, this._offsetY); + const editor = this.getEditor(); + + let isScriptNode = false; + + if (this._data.length === 1) { + + const finder = ScenePlugin.getInstance().getSceneFinder(); + + const asset = this._data[0]; + + isScriptNode = asset instanceof io.FilePath + && finder.isScriptPrefabFile(asset) + || asset instanceof sceneobjects.ScriptNodeExtension; + } + + if (isScriptNode) { + + // We are droping a script node, + // so we should go for every object selected in the scene + // and add the script. + // It is different from adding a regular game object, + // where only one instance is created + + const sel = editor.getSelectedGameObjects(); + + const newSprites = []; + + const script = this._data[0]; + + for (const obj of sel) { + + const sprites = await editor.getDropManager() + .createWithDropEvent([script], 0, 0, [obj]); + + newSprites.push(...sprites); + } + + editor.setSelection(newSprites); + + } else { + + const sprites = await editor.getDropManager() + .createWithDropEvent(this._data, this._offsetX, this._offsetY); - this.getEditor().setSelection(sprites); + editor.setSelection(sprites); + } } } } \ No newline at end of file diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/scriptNode/AddScriptDialog.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/scriptNode/AddScriptDialog.ts index 7335d06dc..472351e39 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/scriptNode/AddScriptDialog.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/scriptNode/AddScriptDialog.ts @@ -70,7 +70,6 @@ namespace phasereditor2d.scene.ui.sceneobjects { this.addOpenButton("Add Script", sel => { this.addScript(sel[0]); - })); this.addCancelButton(); From 344d83dc827fe8e8aac38d2447c12e6d3a494562 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 23 Jun 2023 11:57:31 -0400 Subject: [PATCH 64/72] Updates changelog. --- CHANGELOG.MD | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index d12144917..2a717a7ce 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -15,11 +15,12 @@ * Fixes hit area serialization. * Removes the User Components section and shows user components properties as individual sections: * Renames the Scripts context menu to Scripting and include: - - Add User Component - - Browse User Components + - Add User Component (`M` key) + - Browse User Components (`Shift+M` key) * Removes user component nodes from the Outline view. * Removes the Prefab Instance section, shows the prefab instance user properties as individual sections. * The Replace Texture Frame command responds to the `F` key. +* Fixes adding a script node to all selected game objects. ## v3.61.0 - May 18, 2023 From 942836580bf578a0e1553bd0e902240dc1508db2 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 23 Jun 2023 14:47:28 -0400 Subject: [PATCH 65/72] Update version. --- CHANGELOG.MD | 2 +- source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 2a717a7ce..817c79824 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,6 +1,6 @@ # Change Log -## v3.61.1-dev +## v3.62.0-dev * New Event user property. * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers. diff --git a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts index 8a9597578..449f169a5 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts @@ -323,7 +323,7 @@ namespace phasereditor2d.ide { /* program entry point */ - export const VER = "3.61.1"; + export const VER = "3.62.0-dev"; async function main() { From d2e8c9ec09af02f22a2300074fbfdc87b16e45f5 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Fri, 23 Jun 2023 15:06:02 -0400 Subject: [PATCH 66/72] Updates changelog. --- CHANGELOG.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 817c79824..49b17bd28 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -21,6 +21,7 @@ * Removes the Prefab Instance section, shows the prefab instance user properties as individual sections. * The Replace Texture Frame command responds to the `F` key. * Fixes adding a script node to all selected game objects. +[#223](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/222) Fixed tab-focus on the DOM elements of the user properties. ## v3.61.0 - May 18, 2023 From acdea0dc4bb1638b845c03c960fff7f40c94fc04 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Sun, 25 Jun 2023 22:48:22 -0400 Subject: [PATCH 67/72] Fixes icon updating of the search button of the TextureConfigType. --- .../AbstractDialogPropertyType.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts index 3a2aab0b5..1622df293 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/sceneobjects/userProperties/AbstractDialogPropertyType.ts @@ -52,7 +52,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { const text = section.createStringField(comp, prop); - const btn = this.createSearchButton(() => prop.getValue(section.getSelectionFirstElement()), value => { + const { buttonElement, iconControl } = this.createSearchButton(() => prop.getValue(section.getSelectionFirstElement()), value => { text.value = value; @@ -64,10 +64,14 @@ namespace phasereditor2d.scene.ui.sceneobjects { section.addUpdater(() => { - btn.disabled = !section.isUnlocked(prop); + buttonElement.disabled = !section.isUnlocked(prop); + + const value = prop.getValue(section.getSelectionFirstElement()); + + this.updateIcon(iconControl, value); }); - comp.appendChild(btn); + comp.appendChild(buttonElement); } private createEditorComp() { @@ -83,6 +87,8 @@ namespace phasereditor2d.scene.ui.sceneobjects { private createSearchButton(getValue: () => any, callback: (value: string) => void) { + console.log("createSearchButton") + const iconControl = new controls.IconControl(colibri.ColibriPlugin.getInstance().getIcon(colibri.ICON_FOLDER)); const btn = document.createElement("button"); @@ -102,7 +108,7 @@ namespace phasereditor2d.scene.ui.sceneobjects { } - return btn; + return { buttonElement: btn, iconControl }; } protected async updateIcon(iconControl: controls.IconControl, value: any) { @@ -198,14 +204,18 @@ namespace phasereditor2d.scene.ui.sceneobjects { setValue(inputElement.value); }); + const { buttonElement, iconControl } = this.createSearchButton(getValue, setValue); + + comp.appendChild(buttonElement); + const update = () => { - inputElement.value = getValue(); - }; + const value = getValue(); - const btn = this.createSearchButton(getValue, setValue); + inputElement.value = value; - comp.appendChild(btn); + this.updateIcon(iconControl, value); + }; return { element: comp, From 56fccf1b3ad713dab0c789a58c5451118690c8b7 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 26 Jun 2023 09:00:24 -0400 Subject: [PATCH 68/72] Update version. --- source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts index 449f169a5..6aef27099 100644 --- a/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts +++ b/source/editor/plugins/phasereditor2d.ide/src/IDEPlugin.ts @@ -323,7 +323,7 @@ namespace phasereditor2d.ide { /* program entry point */ - export const VER = "3.62.0-dev"; + export const VER = "3.62.0"; async function main() { From 3054bf5e9dc6795540c675ee2a5aaabef9cec376 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 26 Jun 2023 11:08:31 -0400 Subject: [PATCH 69/72] Allows the `#` comment character in `events.txt` file.\ --- .../plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts index 711d8aa25..07c7c8cd4 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/core/json/SceneFinder.ts @@ -560,7 +560,7 @@ namespace phasereditor2d.scene.core.json { line = line.trim(); - if (line.length === 0) { + if (line.length === 0 || line.startsWith("#")) { continue; } From 0b9a65e7d33f5c2b2819f6d6e9d29f9f08352df9 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Mon, 26 Jun 2023 11:59:33 -0400 Subject: [PATCH 70/72] Fixes dropping script node to an scene. --- .../src/ui/editor/undo/CreateObjectWithAssetOperation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts index ec9eebbf1..42413ff3f 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/undo/CreateObjectWithAssetOperation.ts @@ -34,16 +34,16 @@ namespace phasereditor2d.scene.ui.editor.undo { || asset instanceof sceneobjects.ScriptNodeExtension; } - if (isScriptNode) { + const sel = editor.getSelectedGameObjects(); - // We are droping a script node, + if (isScriptNode && sel.length > 0) { + + // We are dropping a script node, // so we should go for every object selected in the scene // and add the script. // It is different from adding a regular game object, // where only one instance is created - const sel = editor.getSelectedGameObjects(); - const newSprites = []; const script = this._data[0]; From 0358a030f9cb37c5484008865a782d6de8782c8e Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Wed, 28 Jun 2023 11:22:24 -0400 Subject: [PATCH 71/72] Changes "Replace Texture Frame" keys to Shift+F. --- .../src/ui/editor/commands/SceneEditorCommands.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts index c2a45ed22..e456bea34 100644 --- a/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts +++ b/source/editor/plugins/phasereditor2d.scene/src/ui/editor/commands/SceneEditorCommands.ts @@ -1152,6 +1152,7 @@ namespace phasereditor2d.scene.ui.editor.commands { } }, keys: { + shift: true, key: "KeyF" } }); From e0dc0aca84d4798f460914dcb28912fd86b6ea26 Mon Sep 17 00:00:00 2001 From: PhaserEditor2D Date: Thu, 29 Jun 2023 11:53:26 -0400 Subject: [PATCH 72/72] Updates changelog. --- CHANGELOG.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 49b17bd28..c04a752cd 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,6 +1,6 @@ # Change Log -## v3.62.0-dev +## v3.62.0, Jun 29, 2023 * New Event user property. * [#284](https://github.com/PhaserEditor2D/PhaserEditor2D-v3/issues/284) Fixes hit area rendering for containers.