Browse Source

Editor plugins can add items to project and hierarchy context menus and handle their events.

Matt Benic 9 years ago
parent
commit
4fd7403f8d

+ 99 - 4
Script/AtomicEditor/hostExtensions/HostExtensionServices.ts

@@ -23,6 +23,8 @@
 import * as EditorEvents from "../editor/EditorEvents";
 import * as EditorUI from "../ui/EditorUI";
 import MainFramMenu = require("../ui/frames/menus/MainFrameMenu");
+import HierarchyFrameMenu = require("../ui/frames/menus/HierarchyFrameMenu");
+import ProjectFrameMenu = require("../ui/frames/menus/ProjectFrameMenu");
 import ModalOps = require("../ui/modal/ModalOps");
 /**
  * Generic registry for storing Editor Extension Services
@@ -205,12 +207,20 @@ export class UIServicesProvider extends ServicesProvider<Editor.HostExtensions.U
     }
 
     private mainFrameMenu: MainFramMenu = null;
+    private hierarchyFrameMenu: HierarchyFrameMenu = null;
+    private projectFrameMenu: ProjectFrameMenu = null;
     private modalOps: ModalOps;
 
-    init(menu: MainFramMenu, modalOps: ModalOps) {
+    init(mainFrameMenu: MainFramMenu, hierarchyFrameMenu: HierarchyFrameMenu, projectFrameMenu: ProjectFrameMenu, modalOps: ModalOps) {
         // Only set these once
         if (this.mainFrameMenu == null) {
-            this.mainFrameMenu = menu;
+            this.mainFrameMenu = mainFrameMenu;
+        }
+        if (this.hierarchyFrameMenu == null) {
+            this.hierarchyFrameMenu = hierarchyFrameMenu;
+        }
+        if (this.projectFrameMenu == null) {
+            this.projectFrameMenu = projectFrameMenu;
         }
         if (this.modalOps == null) {
             this.modalOps = modalOps;
@@ -235,6 +245,42 @@ export class UIServicesProvider extends ServicesProvider<Editor.HostExtensions.U
         this.mainFrameMenu.removePluginMenuItemSource(id);
     }
 
+    /**
+     * Adds a new menu to the hierarchy context menu
+     * @param  {string} id
+     * @param  {any} items
+     * @return {Atomic.UIMenuItemSource}
+     */
+    createHierarchyContextMenuItemSource(id: string, items: any): Atomic.UIMenuItemSource {
+        return this.hierarchyFrameMenu.createPluginItemSource(id, items);
+    }
+
+    /**
+     * Removes a previously added menu from the hierarchy context menu
+     * @param  {string} id
+     */
+    removeHierarchyContextMenuItemSource(id: string) {
+        this.hierarchyFrameMenu.removePluginItemSource(id);
+    }
+
+    /**
+     * Adds a new menu to the project context menu
+     * @param  {string} id
+     * @param  {any} items
+     * @return {Atomic.UIMenuItemSource}
+     */
+    createProjectContextMenuItemSource(id: string, items: any): Atomic.UIMenuItemSource {
+        return this.projectFrameMenu.createPluginItemSource(id, items);
+    }
+
+    /**
+     * Removes a previously added menu from the project context menu
+     * @param  {string} id
+     */
+    removeProjectContextMenuItemSource(id: string) {
+        this.projectFrameMenu.removePluginItemSource(id);
+    }
+
     /**
      * Disaplays a modal window
      * @param  {Editor.Modal.ModalWindow} window
@@ -248,14 +294,63 @@ export class UIServicesProvider extends ServicesProvider<Editor.HostExtensions.U
      * @param  {string} refId
      * @type {boolean} return true if handled
      */
-    menuItemClicked(refId: string): boolean {
+    menuItemClicked(refid: string): boolean {
         // run through and find any services that can handle this.
         let holdResult = false;
         this.registeredServices.forEach((service) => {
             try {
                 // Verify that the service contains the appropriate methods and that it can handle it
                 if (service.menuItemClicked) {
-                    if (service.menuItemClicked(refId)) {
+                    if (service.menuItemClicked(refid)) {
+                        holdResult = true;
+                    }
+                }
+            } catch (e) {
+               EditorUI.showModalError("Extension Error", `Error detected in extension ${service.name}:\n${e}\n\n ${e.stack}`);
+            }
+        });
+        return holdResult;
+    }
+
+    /**
+     * Called when a context menu item in the hierarchy pane has been clicked
+     * @param  {Atomic.UIWidget} target
+     * @param  {string} refId
+     * @type {boolean} return true if handled
+     */
+    hierarchyContextItemClicked(target: Atomic.UIWidget, refid: string): boolean {
+        // run through and find any services that can handle this.
+        let holdResult = false;
+        this.registeredServices.forEach((service) => {
+            try {
+                // Verify that the service contains the appropriate methods and that it can handle it
+                if (service.hierarchyContextItemClicked) {
+                    if (service.hierarchyContextItemClicked(target, refid)) {
+                        holdResult = true;
+                    }
+                }
+            } catch (e) {
+               EditorUI.showModalError("Extension Error", `Error detected in extension ${service.name}:\n${e}\n\n ${e.stack}`);
+            }
+        });
+        return holdResult;
+    }
+
+
+    /**
+     * Called when a context menu item in the hierarchy pane has been clicked
+     * @param  {Atomic.UIWidget} target
+     * @param  {string} refId
+     * @type {boolean} return true if handled
+     */
+    projectContextItemClicked(target: Atomic.UIWidget, refid: string): boolean {
+        // run through and find any services that can handle this.
+        let holdResult = false;
+        this.registeredServices.forEach((service) => {
+            try {
+                // Verify that the service contains the appropriate methods and that it can handle it
+                if (service.projectContextItemClicked) {
+                    if (service.projectContextItemClicked(target, refid)) {
                         holdResult = true;
                     }
                 }

+ 5 - 1
Script/AtomicEditor/ui/EditorUI.ts

@@ -96,7 +96,11 @@ class EditorUI extends Atomic.ScriptObject {
     this.shortcuts = new Shortcuts();
 
     // Hook the service locator into the event system and give it the ui objects it needs
-    ServiceLocator.uiServices.init(this.mainframe.menu, this.modalOps);
+    ServiceLocator.uiServices.init(
+      this.mainframe.menu, 
+      this.mainframe.hierarchyFrame.menu,
+      this.mainframe.projectframe.menu,
+      this.modalOps);
     ServiceLocator.subscribeToEvents(this.mainframe);
 
     this.subscribeToEvent(EditorEvents.ModalError, (event:EditorEvents.ModalErrorEvent) => {

+ 15 - 3
Script/AtomicEditor/ui/frames/menus/HierarchyFrameMenu.ts

@@ -24,15 +24,20 @@ import strings = require("ui/EditorStrings");
 import EditorEvents = require("editor/EditorEvents");
 import EditorUI = require("ui/EditorUI");
 import MenuItemSources = require("./MenuItemSources");
+import ServiceLocator from "../../../hostExtensions/ServiceLocator";
 
 class HierarchyFrameMenus extends Atomic.ScriptObject {
 
+    contentFolder: string;
+
+    private contextMenuItemSource: Atomic.UIMenuItemSource = null;
+
     constructor() {
 
         super();
 
         MenuItemSources.createMenuItemSource("hierarchy create items", createItems);
-        MenuItemSources.createMenuItemSource("node context general", nodeGeneralContextItems);
+        this.contextMenuItemSource = MenuItemSources.createMenuItemSource("node context general", nodeGeneralContextItems);
 
         this.subscribeToEvent(EditorEvents.ContentFolderChanged, (ev: EditorEvents.ContentFolderChangedEvent) => {
             this.contentFolder = ev.path;
@@ -110,7 +115,8 @@ class HierarchyFrameMenus extends Atomic.ScriptObject {
                 node.scene.sendEvent("SceneEditNodeCreated", { node: newnode });
             }
 
-            return true;
+            // Let plugins handle context
+            return ServiceLocator.uiServices.hierarchyContextItemClicked(target, refid);
         }
 
         return false;
@@ -133,7 +139,13 @@ class HierarchyFrameMenus extends Atomic.ScriptObject {
 
     }
 
-    contentFolder: string;
+    createPluginItemSource(id: string, items: any): Atomic.UIMenuItemSource {
+        return MenuItemSources.createSubMenuItemSource(this.contextMenuItemSource , id, items);
+    }
+
+    removePluginItemSource(id: string) {
+        this.contextMenuItemSource.removeItemWithStr(id);
+    }
 
 }
 

+ 15 - 2
Script/AtomicEditor/ui/frames/menus/ProjectFrameMenu.ts

@@ -24,15 +24,20 @@ import strings = require("ui/EditorStrings");
 import EditorEvents = require("editor/EditorEvents");
 import EditorUI = require("ui/EditorUI");
 import MenuItemSources = require("./MenuItemSources");
+import ServiceLocator from "../../../hostExtensions/ServiceLocator";
 
 class ProjectFrameMenus extends Atomic.ScriptObject {
 
+    contentFolder: string;
+
+    private contextMenuItemSource: Atomic.UIMenuItemSource = null;
+
     constructor() {
 
         super();
 
         MenuItemSources.createMenuItemSource("asset context folder", assetFolderContextItems);
-        MenuItemSources.createMenuItemSource("asset context general", assetGeneralContextItems);
+        this.contextMenuItemSource = MenuItemSources.createMenuItemSource("asset context general", assetGeneralContextItems);
         MenuItemSources.createMenuItemSource("project create items", createItems);
 
         this.subscribeToEvent(EditorEvents.ContentFolderChanged, (ev: EditorEvents.ContentFolderChangedEvent) => {
@@ -106,6 +111,8 @@ class ProjectFrameMenus extends Atomic.ScriptObject {
                 return true;
             }
 
+            // Let plugins handle context
+            return ServiceLocator.uiServices.projectContextItemClicked(target, refid);
         }
 
         return false;
@@ -149,7 +156,13 @@ class ProjectFrameMenus extends Atomic.ScriptObject {
 
     }
 
-    contentFolder: string;
+    createPluginItemSource(id: string, items: any): Atomic.UIMenuItemSource {
+        return MenuItemSources.createSubMenuItemSource(this.contextMenuItemSource , id, items);
+    }
+
+    removePluginItemSource(id: string) {
+        this.contextMenuItemSource.removeItemWithStr(id);
+    }
 
 }
 

+ 7 - 1
Script/TypeScript/EditorWork.d.ts

@@ -254,11 +254,17 @@ declare module Editor.HostExtensions {
     export interface ProjectServicesProvider extends Editor.Extensions.ServicesProvider<ProjectServicesEventListener> { }
 
     export interface UIServicesEventListener extends Editor.Extensions.ServiceEventListener {
-        menuItemClicked?(refId: string): boolean;
+        menuItemClicked?(refid: string): boolean;
+        projectContextItemClicked?(target: Atomic.UIWidget, refid: string): boolean;
+        hierarchyContextItemClicked?(target: Atomic.UIWidget, refid: string): boolean;
     }
     export interface UIServicesProvider extends Editor.Extensions.ServicesProvider<UIServicesEventListener> {
         createPluginMenuItemSource(id: string, items: any): Atomic.UIMenuItemSource;
         removePluginMenuItemSource(id: string);
+        createHierarchyContextMenuItemSource(id: string, items: any): Atomic.UIMenuItemSource;
+        removeHierarchyContextMenuItemSource(id: string);
+        createProjectContextMenuItemSource(id: string, items: any): Atomic.UIMenuItemSource;
+        removeProjectContextMenuItemSource(id: string);
         showModalWindow(windowText: string, uifilename: string, handleWidgetEventCB: (ev: Atomic.UIWidgetEvent) => void): Editor.Modal.ExtensionWindow;
     }
 }