diff --git a/src/core/action-handler.ts b/src/core/action-handler.ts index 8913582..8d32152 100644 --- a/src/core/action-handler.ts +++ b/src/core/action-handler.ts @@ -2,11 +2,11 @@ export interface Action { id: string; label?: string; icon?: string; - shortcut?: string; + shortcuts?: string[]; toggle?: boolean; hold?: boolean; on?: string; - command: () => void; + command?: () => void; state?: () => any; } @@ -20,10 +20,18 @@ export class ActionHandler { public getActions() { return Object.values(this.actions); } public getAction(id: string) { return id in this.actionById ? this.actionById[id] : null; } - public addContainer(id: string, container: HTMLElement) { - this.containers[id] = container; + public setActionCommand(id: string, command: () => void, state?: () => boolean) { + const action = this.getAction(id); + if (!action) { + console.warn(`Could not find action ${id}`); + return; + } + action.command = command; + action.state = state; } + public addContainer(id: string, container: HTMLElement) { this.containers[id] = container; } + public enable() { Object.keys(this.containers).forEach(cid => { const container = this.containers[cid]; @@ -46,10 +54,12 @@ export class ActionHandler { if (!(cid in this.actions)) this.actions[cid] = {}; const container = this.actions[cid]; - if (action.shortcut) { - if (action.shortcut in container) - throw new Error(`There is already an action with shortcut ${action.shortcut}: ${container[action.shortcut].label}`); - container[action.shortcut] = action; + if (action.shortcuts) { + action.shortcuts.forEach(s => { + if (s in container) + throw new Error(`There is already an action with shortcut ${s}: ${container[s].label}`); + container[s] = action; + }); } this.actionById[action.id] = action; @@ -64,7 +74,7 @@ export class ActionHandler { + e.key; if (k in actions) { const action = actions[k]; - action.command(); + action.command?.(); if (action.toggle && action.hold) this._holdingToggleAction = action; e.preventDefault(); @@ -73,7 +83,7 @@ export class ActionHandler { private onKeyUp() { if (!this._holdingToggleAction) return; - this._holdingToggleAction.command(); + this._holdingToggleAction.command?.(); this._holdingToggleAction = null; } } diff --git a/src/core/editor.ts b/src/core/editor.ts index 3f95cce..48b0c00 100644 --- a/src/core/editor.ts +++ b/src/core/editor.ts @@ -1,4 +1,5 @@ import { ComponentTags } from 'component-tags'; +import { Actions } from 'core/actions'; import { EditorData } from 'data/editor-data'; import { InspectorData } from 'data/inspector-data'; import { PhaserMeta } from 'data/phaser-meta'; @@ -22,7 +23,7 @@ class EditorClass { this.inspectorData = this.createInspectorData(); this.meta = new PhaserMeta(); - this.actions = new ActionHandler(); + this.actions = this.createActions(); this.history = new History(this.data); this.prefs = new Preferences(clearPrefs); } @@ -128,6 +129,106 @@ class EditorClass { return data; } + private createActions() { + const actions = new ActionHandler(); + actions.add( + { + id: Actions.TOGGLE_ENABLED, + label: 'edit', + icon: 'fa-edit', + toggle: true, + shortcuts: ['ctrl+F2'] + }, + + { + id: Actions.TOGGLE_SNAP, + label: 'snap', + icon: 'fa-border-all', + toggle: true, + }, + { + id: Actions.TOGGLE_GIZMOS, + label: 'gizmos', + icon: 'fa-vector-square', + toggle: true, + hold: true, + shortcuts: ['ctrl+shift+Shift', 'ctrl+shift+Control'], + }, + { + id: Actions.TOGGLE_GUIDES, + toggle: true, + label: 'guides', + icon: 'fa-compress', + }, + { + id: Actions.UNDO, + label: 'undo', + icon: 'fa-undo-alt', + shortcuts: ['ctrl+z'], + }, + + { + id: Actions.PRINT_OBJECT, + label: 'print', + icon: 'fa-terminal', + shortcuts: ['ctrl+alt+p'], + }, + { + id: Actions.DESELECT, + shortcuts: ['Escape'], + }, + + { + id: Actions.MOVE_UP_1, + shortcuts: ['ArrowUp'], + // command: () => scene.moveSelectedObject(0, -1) + }, + { + id: Actions.MOVE_DOWN_1, + shortcuts: ['ArrowDown'], + // command: () => scene.moveSelectedObject(0, 1) + }, + { + id: Actions.MOVE_LEFT_1, + shortcuts: ['ArrowLeft'], + // command: () => scene.moveSelectedObject(-1, 0) + }, + { + id: Actions.MOVE_RIGHT_1, + shortcuts: ['ArrowRight'], + // command: () => scene.moveSelectedObject(1, 0) + }, + { + id: Actions.MOVE_UP_10, + shortcuts: ['shift+ArrowUp'], + // command: () => scene.moveSelectedObject(0, -10) + }, + { + id: Actions.MOVE_DOWN_10, + shortcuts: ['shift+ArrowDown'], + // command: () => scene.moveSelectedObject(0, 10) + }, + { + id: Actions.MOVE_LEFT_10, + shortcuts: ['shift+ArrowLeft'], + // command: () => scene.moveSelectedObject(-10, 0) + }, + { + id: Actions.MOVE_RIGHT_10, + shortcuts: ['shift+ArrowRight'], + // command: () => scene.moveSelectedObject(10, 0) + }, + ); + + return actions; + } + + public setupInitialActions() { + const actions = this.actions; + this.prefs.setupActions(actions); + this.history.setupActions(actions); + this.data.setupActions(actions); + } public enable() { this.actions.enable(); diff --git a/src/core/history.ts b/src/core/history.ts index 07142b1..ac33ac7 100644 --- a/src/core/history.ts +++ b/src/core/history.ts @@ -1,4 +1,6 @@ import { DataOrigin, EditorData } from '../data/editor-data'; +import { ActionHandler } from './action-handler'; +import { Actions } from './actions'; export interface HistoryEntry { obj: PIXI.DisplayObject; @@ -16,6 +18,10 @@ export class History { constructor(private readonly data: EditorData) { } + public setupActions(actions: ActionHandler) { + actions.setActionCommand(Actions.UNDO, this.undo.bind(this)); + } + public prepare(obj: PIXI.DisplayObject, properties: { [id: string]: any }) { const entry = this.holdingEntry = { obj, properties }; Object.keys(entry.properties).forEach(k => diff --git a/src/core/preferences.ts b/src/core/preferences.ts index 98f265a..e9a2c27 100644 --- a/src/core/preferences.ts +++ b/src/core/preferences.ts @@ -1,4 +1,6 @@ import { OnlyProperties, PanelSide } from 'types'; +import { ActionHandler } from './action-handler'; +import { Actions } from './actions'; export type PreferenceKey = OnlyProperties; @@ -35,13 +37,13 @@ export class Preferences { this.save('guides', value); } - private _referenceImage = false; + private _refImage = false; - public get referenceImage() { return this._referenceImage; } + public get refImage() { return this._refImage; } - public set referenceImage(value: boolean) { - this._referenceImage = value; - this.notifyListeners('referenceImage', value); + public set refImage(value: boolean) { + this._refImage = value; + this.notifyListeners('refImage', value); this.save('referenceImage', value); } @@ -55,7 +57,15 @@ export class Preferences { this._snap = this.load('snap', true); this._gizmos = this.load('gizmos', true); this._guides = this.load('guides', false); - this._referenceImage = this.load('referenceImage', false); + this._refImage = this.load('refImage', false); + } + + // hmm... this is weird + public setupActions(actions: ActionHandler) { + actions.setActionCommand(Actions.TOGGLE_SNAP, () => this.snap = !this._snap, () => this._snap); + actions.setActionCommand(Actions.TOGGLE_GIZMOS, () => this.gizmos = !this._gizmos, () => this._gizmos); + actions.setActionCommand(Actions.TOGGLE_GUIDES, () => this.guides = !this._guides, () => this._guides); + actions.setActionCommand(Actions.TOGGLE_REF_IMAGE, () => this.refImage = !this._refImage, () => this._refImage); } diff --git a/src/data/editor-data.ts b/src/data/editor-data.ts index 05c27f9..f5dc3de 100644 --- a/src/data/editor-data.ts +++ b/src/data/editor-data.ts @@ -1,3 +1,6 @@ +import { ActionHandler } from 'core/action-handler'; +import { Actions } from 'core/actions'; + export enum DataOrigin { ACTION = 0, SCENE = 1, @@ -48,4 +51,11 @@ export class EditorData { this.onPropertyChanged.dispatch(e.from, k, e.value, this._selectedObject); }); } + + public setupActions(actions: ActionHandler) { + actions.setActionCommand(Actions.DESELECT, () => this.selectObject(null, DataOrigin.ACTION)); + actions.setActionCommand(Actions.PRINT_OBJECT, () => { + if (this._selectedObject) console.info(this._selectedObject); + }) + } } diff --git a/src/editor-view/actions/reference-image/reference-image-panel.ts b/src/editor-view/actions/reference-image/reference-image-panel.ts index 6c4ee45..9722639 100644 --- a/src/editor-view/actions/reference-image/reference-image-panel.ts +++ b/src/editor-view/actions/reference-image/reference-image-panel.ts @@ -1,7 +1,7 @@ +import { ComponentTags } from 'component-tags'; import { Actions } from 'core/actions'; import { Editor } from 'core/editor'; import { PreferenceKey } from 'core/preferences'; -import { ComponentTags } from 'component-tags'; import { ActionButton } from '../button/action-button'; import './reference-image-panel.scss'; @@ -22,12 +22,12 @@ export class ReferenceImagePanel extends HTMLElement { this.appendChild(slider); Editor.prefs.onPreferenceChanged.add(this.onPreferenceChanged, this); - this.onPreferenceChanged('referenceImage', Editor.prefs.referenceImage); + this.onPreferenceChanged('refImage', Editor.prefs.refImage); // slider.value = Editor.referenceImage.alpha.toString(); } private onPreferenceChanged(pref: PreferenceKey, value: any) { - if (pref !== 'referenceImage') return; + if (pref !== 'refImage') return; if (value) this.slider.removeAttribute('disabled'); else this.slider.setAttribute('disabled', 'true'); } diff --git a/src/editor-view/editor-view.ts b/src/editor-view/editor-view.ts index a766ff4..da0b7f1 100644 --- a/src/editor-view/editor-view.ts +++ b/src/editor-view/editor-view.ts @@ -1,4 +1,5 @@ import { ComponentTags } from 'component-tags'; +import { ActionHandler } from 'core/action-handler'; import { Editor } from 'core/editor'; import { DataOrigin } from 'data/editor-data'; import { ActionsToolbar } from './actions/actions-toolbar'; @@ -32,6 +33,8 @@ export class EditorView extends Widget { this.panels.forEach(panel => panel.init(game, root)); } + public setupActions(actions: ActionHandler) { } + private createElements() { const leftPanel = this.appendChild(document.createElement(ComponentTags.Panel) as Panel); leftPanel.setSide('left'); diff --git a/src/editor-view/inspector/inspector.ts b/src/editor-view/inspector/inspector.ts index d48f3ec..14f7f4c 100644 --- a/src/editor-view/inspector/inspector.ts +++ b/src/editor-view/inspector/inspector.ts @@ -1,5 +1,5 @@ +import { DataOrigin } from 'data/editor-data'; import { Widget } from 'editor-view/widget/widget'; -import { DataOrigin } from 'index'; import './inspector.scss'; export abstract class Inspector extends Widget { diff --git a/src/editor.window.ts b/src/editor.window.ts index bb833fc..b578c30 100644 --- a/src/editor.window.ts +++ b/src/editor.window.ts @@ -1,7 +1,6 @@ import { ComponentTags } from 'component-tags'; import { Actions } from 'core/actions'; import { Editor } from 'core/editor'; -import { DataOrigin } from 'data/editor-data'; import { DisabledUI } from 'disabled/disabled-ui'; import { EditorView } from 'editor-view/editor-view'; import { PluginConfig } from 'plugin'; @@ -13,6 +12,7 @@ import { SceneView } from 'scene-view/scene-view'; // * and another for the workflow export class EditorWindow { private _initialized = false; + private _isEnabled = false; private disabledUI: DisabledUI; private sceneView: SceneView; @@ -43,11 +43,28 @@ export class EditorWindow { // if (this.refImage) this.setupRefImage(this.refImage, this.root); + this.setupInitialActions(); // this.setupActions(scene); // Editor.actions.addContainer('body', document.body); } + private setupInitialActions() { + Editor.setupInitialActions(); + + const actions = Editor.actions; + actions.setActionCommand(Actions.TOGGLE_ENABLED, + () => this._isEnabled ? this.hide() : this.show(), + () => this._isEnabled); + + this.editorView.setupActions(actions); + this.sceneView.setupActions(actions); + + actions.addContainer('body', document.body); + } + public show() { + if (this._isEnabled) return; + this._isEnabled = true; this.disabledUI.disable(); if (!this._initialized) this.init(); @@ -58,6 +75,8 @@ export class EditorWindow { } private hide() { + if (!this._isEnabled) return; + this._isEnabled = false; Editor.disable(); this.sceneView.disable(); this.editorView.disable(); @@ -66,118 +85,108 @@ export class EditorWindow { if (this.onhide) this.onhide(); } - private setupActions(scene: SceneView) { - const { history, prefs } = Editor; - Editor.actions.add( - { - id: Actions.UNDO, - label: 'undo', - icon: 'fa-undo-alt', - shortcut: 'ctrl+z', - command: history.undo.bind(history) - }, - { - id: Actions.MOVE_UP_1, - shortcut: 'ArrowUp', - command: () => scene.moveSelectedObject(0, -1) - }, - { - id: Actions.MOVE_DOWN_1, - shortcut: 'ArrowDown', - command: () => scene.moveSelectedObject(0, 1) - }, - { - id: Actions.MOVE_LEFT_1, - shortcut: 'ArrowLeft', - command: () => scene.moveSelectedObject(-1, 0) - }, - { - id: Actions.MOVE_RIGHT_1, - shortcut: 'ArrowRight', - command: () => scene.moveSelectedObject(1, 0) - }, - { - id: Actions.MOVE_UP_10, - shortcut: 'shift+ArrowUp', - command: () => scene.moveSelectedObject(0, -10) - }, - { - id: Actions.MOVE_DOWN_10, - shortcut: 'shift+ArrowDown', - command: () => scene.moveSelectedObject(0, 10) - }, - { - id: Actions.MOVE_LEFT_10, - shortcut: 'shift+ArrowLeft', - command: () => scene.moveSelectedObject(-10, 0) - }, - { - id: Actions.MOVE_RIGHT_10, - shortcut: 'shift+ArrowRight', - command: () => scene.moveSelectedObject(10, 0) - }, - { - id: Actions.TOGGLE_SNAP, - label: 'snap', - icon: 'fa-border-all', - toggle: true, - command: () => prefs.snap = !prefs.snap, - state: () => prefs.snap, - }, - { - id: Actions.TOGGLE_GIZMOS, - label: 'gizmos', - icon: 'fa-vector-square', - toggle: true, - hold: true, - shortcut: 'ctrl+shift+Shift', - command: () => prefs.gizmos = !prefs.gizmos, - state: () => prefs.gizmos, - }, - { - id: Actions.TOGGLE_GIZMOS, - label: 'gizmos', - icon: 'fa-vector-square', - toggle: true, - hold: true, - shortcut: 'ctrl+shift+Control', - command: () => prefs.gizmos = !prefs.gizmos, - state: () => prefs.gizmos, - }, - { - id: Actions.TOGGLE_GUIDES, - toggle: true, - label: 'guides', - icon: 'fa-compress', - command: () => prefs.guides = !prefs.guides, - state: () => prefs.guides, - }, - { - id: Actions.TOGGLE_ENABLED, - label: 'edit', - icon: 'fa-edit', - toggle: true, - command: this.hide.bind(this), - state: () => true, - }, - { - id: Actions.PRINT_OBJECT, - label: 'print', - icon: 'fa-terminal', - shortcut: 'ctrl+alt+p', - command: () => { - if (Editor.data.selectedObject) { - console.info(Editor.data.selectedObject); - } - } - }, - { - id: Actions.DESELECT, - shortcut: 'Escape', - command: () => Editor.data.selectObject(null, DataOrigin.ACTION) - }, - ); - } + // private setupActions(scene: SceneView) { + // const { history, prefs } = Editor; + // Editor.actions.add( + // { + // id: Actions.UNDO, + // label: 'undo', + // icon: 'fa-undo-alt', + // shortcuts: ['ctrl+z'], + // command: history.undo.bind(history) + // }, + // { + // id: Actions.MOVE_UP_1, + // shortcuts: ['ArrowUp'], + // command: () => scene.moveSelectedObject(0, -1) + // }, + // { + // id: Actions.MOVE_DOWN_1, + // shortcuts: ['ArrowDown'], + // command: () => scene.moveSelectedObject(0, 1) + // }, + // { + // id: Actions.MOVE_LEFT_1, + // shortcuts: ['ArrowLeft'], + // command: () => scene.moveSelectedObject(-1, 0) + // }, + // { + // id: Actions.MOVE_RIGHT_1, + // shortcuts: ['ArrowRight'], + // command: () => scene.moveSelectedObject(1, 0) + // }, + // { + // id: Actions.MOVE_UP_10, + // shortcuts: ['shift+ArrowUp'], + // command: () => scene.moveSelectedObject(0, -10) + // }, + // { + // id: Actions.MOVE_DOWN_10, + // shortcuts: ['shift+ArrowDown'], + // command: () => scene.moveSelectedObject(0, 10) + // }, + // { + // id: Actions.MOVE_LEFT_10, + // shortcuts: ['shift+ArrowLeft'], + // command: () => scene.moveSelectedObject(-10, 0) + // }, + // { + // id: Actions.MOVE_RIGHT_10, + // shortcuts: ['shift+ArrowRight'], + // command: () => scene.moveSelectedObject(10, 0) + // }, + // { + // id: Actions.TOGGLE_SNAP, + // label: 'snap', + // icon: 'fa-border-all', + // toggle: true, + // command: () => prefs.snap = !prefs.snap, + // state: () => prefs.snap, + // }, + // { + // id: Actions.TOGGLE_GIZMOS, + // label: 'gizmos', + // icon: 'fa-vector-square', + // toggle: true, + // hold: true, + // shortcuts: ['ctrl+shift+Shift', 'ctrl+shift+Control'], + // command: () => prefs.gizmos = !prefs.gizmos, + // state: () => prefs.gizmos, + // }, + // { + // id: Actions.TOGGLE_GUIDES, + // toggle: true, + // label: 'guides', + // icon: 'fa-compress', + // command: () => prefs.guides = !prefs.guides, + // state: () => prefs.guides, + // }, + // { + // id: Actions.TOGGLE_ENABLED, + // label: 'edit', + // icon: 'fa-edit', + // toggle: true, + // command: this.hide.bind(this), + // state: () => true, + // }, + // { + // id: Actions.PRINT_OBJECT, + // label: 'print', + // icon: 'fa-terminal', + // shortcuts: ['ctrl+alt+p'], + // command: () => { + // if (Editor.data.selectedObject) { + // console.info(Editor.data.selectedObject); + // } + // } + // }, + // { + // id: Actions.DESELECT, + // shortcuts: ['Escape'], + // command: () => Editor.data.selectObject(null, DataOrigin.ACTION) + // }, + // ); + // } // private setupRefImage(refImage: PIXI.Sprite, root: Container) { // Editor.referenceImage = new ReferenceImage(this.game, refImage, root); diff --git a/src/scene-view/reference-image.ts b/src/scene-view/reference-image.ts index 1edea0d..8511bf8 100644 --- a/src/scene-view/reference-image.ts +++ b/src/scene-view/reference-image.ts @@ -14,11 +14,11 @@ export class ReferenceImage extends Phaser.Group { this._parent = root; Editor.prefs.onPreferenceChanged.add(this.onPreferenceChanged, this); - this.onPreferenceChanged('referenceImage', Editor.prefs.referenceImage); + this.onPreferenceChanged('refImage', Editor.prefs.refImage); } private onPreferenceChanged(pref: PreferenceKey, value: any) { - if (pref !== 'referenceImage') return; + if (pref !== 'refImage') return; if (value) this.show(); else this.hide(); } diff --git a/src/scene-view/scene-view.ts b/src/scene-view/scene-view.ts index 609fdce..539f9c2 100644 --- a/src/scene-view/scene-view.ts +++ b/src/scene-view/scene-view.ts @@ -1,3 +1,5 @@ +import { ActionHandler } from 'core/action-handler'; +import { Actions } from 'core/actions'; import { Editor } from 'core/editor'; import { DataOrigin } from 'data/editor-data'; import { DragUtil } from '../util/drag.util'; @@ -46,6 +48,18 @@ export class SceneView extends Phaser.Group { Editor.data.onSelectedObjectChanged.add(this.onObjectSelected.bind(this)); } + public setupActions(actions: ActionHandler) { + actions.setActionCommand(Actions.MOVE_UP_1, () => this.moveSelectedObject(0, -1)); + actions.setActionCommand(Actions.MOVE_DOWN_1, () => this.moveSelectedObject(0, 1)); + actions.setActionCommand(Actions.MOVE_LEFT_1, () => this.moveSelectedObject(-1, 0)); + actions.setActionCommand(Actions.MOVE_RIGHT_1, () => this.moveSelectedObject(1, 0)); + + actions.setActionCommand(Actions.MOVE_UP_10, () => this.moveSelectedObject(0, -10)); + actions.setActionCommand(Actions.MOVE_DOWN_10, () => this.moveSelectedObject(0, 10)); + actions.setActionCommand(Actions.MOVE_LEFT_10, () => this.moveSelectedObject(-10, 0)); + actions.setActionCommand(Actions.MOVE_RIGHT_10, () => this.moveSelectedObject(10, 0)); + } + public enable(root: Container, parent: Phaser.Stage) { this.root = root; if (this.parent === parent) return;