TSExample.plugin.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /// <reference path="../../typings/Atomic/Atomic.d.ts" />
  2. const ExamplePluginUILabel = "TS Example Plugin";
  3. const ExamplePluginTBPath = "EditorData/Example.tb.txt";
  4. const InfoboxTBPath = "EditorData/Infobox.tb.txt";
  5. class CustomEditorBuilder implements Editor.Extensions.ResourceEditorBuilder {
  6. /**
  7. * Returns true if this builder can generate an editor for this resource type
  8. */
  9. canHandleResource(resourcePath: string) {
  10. return resourcePath.indexOf("custom.editor.txt") > 0;
  11. }
  12. /**
  13. * Full path is the fully qualified path from the root of the filesystem. In order to take advantage
  14. * of the resource caching system, let's trim it down to just the path inside the resources directory
  15. * including the Resources directory so that the casing is correct
  16. */
  17. private getNormalizedPath(path: string) {
  18. const RESOURCES_MARKER = "resources/";
  19. return path.substring(path.toLowerCase().indexOf(RESOURCES_MARKER));
  20. }
  21. /**
  22. * Generates a resource editor for the provided resource type
  23. * @param resourcePath
  24. * @param tabContainer
  25. */
  26. getEditor(resourceFrame: Atomic.UIWidget, resourcePath: string, tabContainer: Atomic.UITabContainer) : Editor.ResourceEditor {
  27. // point to a custom page
  28. const editorUrl = "atomic://" + ToolCore.toolSystem.project.resourcePath + "EditorData/customEditor.html";
  29. const editor = new Editor.JSResourceEditor(resourcePath, tabContainer, editorUrl);
  30. // one time subscriptions waiting for the web view to finish loading. This event
  31. // actually hits the editor instance before we can hook it, so listen to it on the
  32. // frame and then unhook it
  33. editor.subscribeToEvent("WebViewLoadEnd", (data) => {
  34. editor.unsubscribeFromEvent("WebViewLoadEnd");
  35. const webClient = editor.webView.webClient;
  36. webClient.executeJavaScript(`HOST_loadCode("atomic://${this.getNormalizedPath(editor.fullPath)}");`);
  37. });
  38. editor.subscribeToEvent("DeleteResourceNotification", (data) => {
  39. const webClient = editor.webView.webClient;
  40. webClient.executeJavaScript(`HOST_resourceDeleted("atomic://${this.getNormalizedPath(data.path)}");`);
  41. });
  42. editor.subscribeToEvent("UserPreferencesChangedNotification", (data) => {
  43. let prefsPath = ToolCore.toolSystem.project.userPrefsFullPath;
  44. if (Atomic.fileSystem.fileExists(prefsPath)) {
  45. // Get a reference to the web client so we can call the load preferences method
  46. const webClient = editor.webView.webClient;
  47. webClient.executeJavaScript(`HOST_loadPreferences("atomic://${prefsPath}");`);
  48. }
  49. });
  50. return editor;
  51. }
  52. }
  53. const customEditorBuilder = new CustomEditorBuilder();
  54. class TSExamplePluginService implements Editor.HostExtensions.HostEditorService, Editor.HostExtensions.ProjectServicesEventListener, Editor.HostExtensions.UIServicesEventListener {
  55. name: string = "TSExampleService";
  56. description: string = "This service demonstrates plugin functionality functionality.";
  57. private serviceLocator: Editor.HostExtensions.HostServiceLocator = null;
  58. private extensionWindow: Editor.Modal.ExtensionWindow = null;
  59. private helloLabel: Atomic.UITextField;
  60. private nameField: Atomic.UIEditField;
  61. private lastObjectName: string = null;
  62. private totalUses = 0;
  63. initialize(serviceLoader: Editor.HostExtensions.HostServiceLocator) {
  64. Atomic.print("TSExamplePluginService.initialize");
  65. this.serviceLocator = (serviceLoader);
  66. if (this.serviceLocator) {
  67. this.serviceLocator.projectServices.register(this);
  68. this.serviceLocator.uiServices.register(this);
  69. }
  70. }
  71. projectUnloaded() {
  72. this.serviceLocator.uiServices.removeProjectContextMenuItemSource(ExamplePluginUILabel);
  73. this.serviceLocator.uiServices.removeHierarchyContextMenuItemSource(ExamplePluginUILabel);
  74. this.serviceLocator.uiServices.removePluginMenuItemSource(ExamplePluginUILabel);
  75. this.serviceLocator.uiServices.unregisterCustomEditor(customEditorBuilder);
  76. Atomic.print("TSExamplePluginService.projectUnloaded");
  77. if (this.serviceLocator) {
  78. this.serviceLocator.projectServices.unregister(this);
  79. this.serviceLocator.uiServices.unregister(this);
  80. }
  81. }
  82. projectLoaded(ev: Editor.EditorEvents.LoadProjectEvent) {
  83. Atomic.print("TSExamplePluginService.projectLoaded");
  84. this.serviceLocator.uiServices.createPluginMenuItemSource(ExamplePluginUILabel, { "Open" : ["tsexampleplugin open"] });
  85. this.serviceLocator.uiServices.createHierarchyContextMenuItemSource(ExamplePluginUILabel, { "Get name" : ["tsexampleplugin hierarchy context"]});
  86. this.serviceLocator.uiServices.createProjectContextMenuItemSource(ExamplePluginUILabel, { "Get name" : ["tsexampleplugin project context"]});
  87. this.totalUses = this.serviceLocator.projectServices.getUserPreference(this.name, "UsageCount", 0);
  88. this.serviceLocator.uiServices.registerCustomEditor(customEditorBuilder);
  89. }
  90. playerStarted() {
  91. Atomic.print("TSExamplePluginService.playerStarted");
  92. }
  93. menuItemClicked(refId: string): boolean {
  94. Atomic.print("TSExamplePluginService.menuItemClicked: " + refId);
  95. if (refId == "tsexampleplugin open") {
  96. this.extensionWindow = this.serviceLocator.uiServices.showModalWindow(
  97. ExamplePluginUILabel, ExamplePluginTBPath, this.handleWidgetEvent);
  98. this.getWidgets();
  99. return true;
  100. }
  101. return false;
  102. }
  103. hierarchyContextItemClicked(node: Atomic.Node, refid: string): boolean {
  104. Atomic.print("TSExamplePluginService.hierarchyContextItemClicked: " + node.name + " " + refid);
  105. if (refid == "tsexampleplugin hierarchy context") {
  106. this.lastObjectName = "node " + node.name;
  107. this.showInfobox("Hierarchy Item Selected ", `Node: '${node.name}' was selected.`);
  108. return true;
  109. }
  110. return false;
  111. }
  112. projectContextItemClicked(asset: ToolCore.Asset, refid: string): boolean {
  113. Atomic.print("TSExamplePluginService.projectContextItemClicked: " + asset.name + " " + refid);
  114. if (refid == "tsexampleplugin project context") {
  115. this.lastObjectName = "asset " + asset.name;
  116. this.showInfobox("Project Asset Selected", `Asset: '${asset.name}' was selected.`);
  117. return true;
  118. }
  119. return false;
  120. }
  121. getWidgets() {
  122. if (!this.extensionWindow) {
  123. return;
  124. }
  125. this.helloLabel = <Atomic.UITextField>this.extensionWindow.getWidget("example_hello");
  126. this.nameField = <Atomic.UIEditField>this.extensionWindow.getWidget("example_name");
  127. if (this.lastObjectName) {
  128. this.nameField.text = this.lastObjectName;
  129. this.lastObjectName = null;
  130. }
  131. }
  132. showInfobox(title: string, msg: string) {
  133. const infobox = this.serviceLocator.uiServices.showModalWindow(
  134. title, InfoboxTBPath, (ev: Atomic.UIWidgetEvent) => {
  135. if (ev.type == Atomic.UI_EVENT_TYPE_CLICK && ev.target.id == "infobox_ok") {
  136. infobox.hide();
  137. return true;
  138. }
  139. });
  140. const msgLabel = <Atomic.UITextField>infobox.getWidget("infobox_msg");
  141. msgLabel.text = msg;
  142. }
  143. handleWidgetEvent = (ev: Atomic.UIWidgetEvent): boolean => { // => notation used to bind "this" to the method
  144. if (!this.extensionWindow) {
  145. return;
  146. }
  147. if (ev.type == Atomic.UI_EVENT_TYPE_CLICK) {
  148. if (ev.target.id == "example_cancel") {
  149. this.extensionWindow.hide();
  150. this.extensionWindow = null;
  151. return true;
  152. }
  153. if (ev.target.id == "example_speak") {
  154. this.serviceLocator.projectServices.setUserPreference(this.name, "UsageCount", ++this.totalUses);
  155. this.helloLabel.text = `Hello ${this.nameField.text}, This was used ${this.totalUses} times.`;
  156. return true;
  157. }
  158. }
  159. return false;
  160. };
  161. }
  162. export default new TSExamplePluginService();