Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Editor Extensions

Shaddock Heath edited this page Feb 21, 2017 · 2 revisions

Background

Atomic has an editor extension capability which will allow specially constructed TypeScript/JavaScript plugin files to be hooked into the editor once a project is loaded. The extension mechanism currently has the following features:

  • Scripts can be written in JavaScript or TypeScript
  • Scripts run in the same process as the editor
  • Menu items can be added to the Developer->Plugins menu of the editor
  • Menu items can be added to the right+click menu on files
  • Menu items can be added to the right+click menu on the Hierarchy
  • Plugins have access to the active editor scene
  • Plugins have access to read/write project preferences
  • Plugins can implement their own resource editors

An example exists in the examples repository in the Editor Plugins folder.

Setup

To get started, you will need to create a new 2D TypeScript project in the editor and then create a new folder called: EditorData under Resources

This folder is what the editor looks at to determine if there are any plugins to load. Each plugin must follow the naming convention: *.plugin.js and will be loaded up when the project is opened.

Example: Adding a menu

A simple example will be to add a menu to the developer menu. This example will be written in TypeScript.

Create a new script file called: mymenu.plugin.ts under the EditorData folder.

Replace the contents with the following:

class MyMenuPlugin extends Atomic.ScriptObject 
                   implements Editor.HostExtensions.HostEditorService,
                              Editor.HostExtensions.UIServicesEventListener, 
                              Editor.HostExtensions.ProjectServicesEventListener {

    // Define the name and description of the plugin.
    name = "MyMenuPlugin";
    description = "Simple example of a menu";

    private serviceLocator: Editor.HostExtensions.HostServiceLocator;

    /**
     * Called when the plugin is first loaded by the editor.  A reference to the
     * service locator interface will be passed to the initialization routine so that
     * it can 'talk back' to the editor.
     *
     * @param {Editor.HostExtensions.HostServiceLocator} serviceLocator
     *
     * @memberOf MyMenuPlugin
     */
    initialize(serviceLocator: Editor.HostExtensions.HostServiceLocator) {
        // some debug
        console.log(`${this.name}.initialize`);
        this.serviceLocator = serviceLocator;
    }
}

export default new MyMenuPlugin();

Register with service event listeners

This is a minimalist plugin. It activates, but does not do anything. In order for the plugin to start interacting with the editor, it needs to register itself with various editor subsystems. In this example, we want to register with the ProjectServicesEventListener and UIServicesEventListener.

Add the following to the initialize method:

this.serviceLocator.uiServices.register(this);
this.serviceLocator.projectServices.register(this);

At this point, you can add any of the handlers that are available in the UIServicesEventListener and ProjectServicesEventListener

Listen for the Project Loaded event

When the project loads, we want to attach our menu item to the menu. To do this, we will hook into the Project Loaded Event which will be called by the editor and then call a uiServices method to add the menu:

projectLoaded(ev: Editor.EditorLoadProjectEvent) {
    // some debug
    console.log(`${this.name}.projectLoaded`);
    this.serviceLocator.uiServices.createPluginMenuItemSource("My Menu", { "Open" : [`${this.name}.open.myaction`] });
}

We also want to make sure the menu is removed and we unregister from the editor when we close the project:

projectUnloaded() {
    // some debug
    console.log(`${this.name}.projectUnloaded`);

    this.serviceLocator.uiServices.removePluginMenuItemSource("My Menu");
    this.serviceLocator.projectServices.unregister(this);
    this.serviceLocator.uiServices.unregister(this);
    this.unsubscribeFromAllEvents();
}

Perform an action when the menu is clicked

Finally, we want to actually do something when the menu is clicked. To do that, we need to implement the menuItemClicked method:

menuItemClicked(refId: string): boolean {
    // some debug
    console.log(`${this.name}.menuItemClicked: ${refId}`);

    if (refId == `${this.name}.open.myaction`) {

        // Here we can launch our own dialog, or perform some kind
        // of action.  But let's just throw an alert
        this.serviceLocator.uiServices.showModalError("Alert", "Clicked!");    

        // Return true to indicate that we handled the click event
        return true;
    }
    return false;
}

In order for this to be picked up by the editor, you will need to transpile the typescript to javascript. This can be done by clicking the Developer->Plugins->TypeScript->Compile Project menu item.

Once it's transpiled, you will need to close your project and re-open it for the changes to be recognized. Click the Developer->Plugins->MyMenu->Open menu item and then you can see the Clicked message alert.

Clone this wiki locally