HierarchyFrame.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import HierarchyFrameMenu = require("./menus/HierarchyFrameMenu");
  2. import MenuItemSources = require("./menus/MenuItemSources");
  3. import EditorEvents = require("editor/EditorEvents");
  4. var IconTemporary = "ComponentBitmap";
  5. class HierarchyFrame extends Atomic.UIWidget {
  6. scene: Atomic.Scene = null;
  7. hierList: Atomic.UIListView;
  8. menu: HierarchyFrameMenu;
  9. nodeIDToItemID = {};
  10. constructor(parent: Atomic.UIWidget) {
  11. super();
  12. this.menu = new HierarchyFrameMenu();
  13. this.load("AtomicEditor/editor/ui/hierarchyframe.tb.txt");
  14. this.gravity = Atomic.UI_GRAVITY_TOP_BOTTOM;
  15. var hierarchycontainer = parent.getWidget("hierarchycontainer");
  16. hierarchycontainer.addChild(this);
  17. hierarchycontainer = this.getWidget("hierarchycontainer");
  18. var hierList = this.hierList = new Atomic.UIListView();
  19. hierList.rootList.id = "hierList_";
  20. hierarchycontainer.addChild(hierList);
  21. this.subscribeToEvent(this, "WidgetEvent", (data) => this.handleWidgetEvent(data));
  22. this.subscribeToEvent(EditorEvents.ActiveNodeChange, (data) => {
  23. if (data.node)
  24. this.hierList.selectItemByID(data.node.id.toString());
  25. });
  26. this.subscribeToEvent(EditorEvents.ActiveSceneChange, (data) => this.handleActiveSceneChanged(data));
  27. // handle dropping on hierarchy, moving node, dropping prefabs, etc
  28. this.subscribeToEvent(this.hierList.rootList, "DragEnded", (data) => this.handleDragEnded(data));
  29. this.subscribeToEvent(EditorEvents.SceneClosed, (ev: EditorEvents.SceneClosedEvent) => {
  30. if (ev.scene == this.scene) {
  31. this.unsubscribeFromEvents(this.scene);
  32. this.scene = null;
  33. this.populate();
  34. }
  35. });
  36. this.subscribeToEvent("ComponentAdded", (ev: Atomic.ComponentAddedEvent) => {
  37. if (!ev.component || ev.component.typeName != "PrefabComponent") return;
  38. var node = ev.node;
  39. var itemID = this.nodeIDToItemID[node.id];
  40. if (itemID) {
  41. this.hierList.setItemTextSkin(node.id.toString(), "HierarchyPrefabText");
  42. }
  43. });
  44. this.subscribeToEvent("ComponentRemoved", (ev: Atomic.ComponentRemovedEvent) => {
  45. if (!ev.component || ev.component.typeName != "PrefabComponent") return;
  46. var node = ev.node;
  47. var itemID = this.nodeIDToItemID[node.id];
  48. if (itemID) {
  49. this.hierList.setItemTextSkin(node.id.toString(), "Folder");
  50. }
  51. });
  52. this.subscribeToEvent("TemporaryChanged", (ev: Atomic.TemporaryChangedEvent) => {
  53. // this can happen on a temporary status change on a non-scripted class instance
  54. if (!ev.serializable) {
  55. return;
  56. }
  57. if (ev.serializable.typeName == "Node") {
  58. var node = <Atomic.Node>ev.serializable;
  59. var itemID = this.nodeIDToItemID[node.id];
  60. if (itemID) {
  61. this.hierList.setItemIcon(node.id.toString(), node.isTemporary() ? IconTemporary : "");
  62. }
  63. }
  64. });
  65. }
  66. handleNodeAdded(ev: Atomic.NodeAddedEvent) {
  67. var node = ev.node;
  68. if (this.filterNode(node))
  69. return;
  70. if (!node.parent || node.scene != this.scene)
  71. return;
  72. var parentID = this.nodeIDToItemID[node.parent.id];
  73. var childItemID = this.recursiveAddNode(parentID, node);
  74. this.nodeIDToItemID[node.id] = childItemID;
  75. }
  76. handleNodeRemoved(ev: Atomic.NodeRemovedEvent) {
  77. // on close
  78. if (!this.scene)
  79. return;
  80. var node = ev.node;
  81. if (this.filterNode(node))
  82. return;
  83. delete this.nodeIDToItemID[node.id];
  84. if (!node.parent || node.scene != this.scene)
  85. return;
  86. this.hierList.deleteItemByID(node.id.toString());
  87. var selectedId = Number(this.hierList.rootList.selectedItemID);
  88. var selectedNode = this.scene.getNode(selectedId);
  89. if (selectedNode == node) {
  90. this.sendEvent(EditorEvents.ActiveNodeChange, { node: ev.parent ? ev.parent : this.scene });
  91. }
  92. }
  93. handleActiveSceneChanged(data) {
  94. if (this.scene)
  95. this.unsubscribeFromEvents(this.scene);
  96. // clear selected node
  97. this.sendEvent(EditorEvents.ActiveNodeChange, { node: null });
  98. this.scene = <Atomic.Scene>data.scene;
  99. this.populate();
  100. if (this.scene) {
  101. this.subscribeToEvent(this.scene, "NodeAdded", (ev: Atomic.NodeAddedEvent) => this.handleNodeAdded(ev));
  102. this.subscribeToEvent(this.scene, "NodeRemoved", (ev: Atomic.NodeRemovedEvent) => this.handleNodeRemoved(ev));
  103. this.subscribeToEvent(this.scene, "NodeNameChanged", (ev: Atomic.NodeNameChangedEvent) => {
  104. this.hierList.setItemText(ev.node.id.toString(), ev.node.name);
  105. });
  106. }
  107. }
  108. handleWidgetEvent(data: Atomic.UIWidgetEvent): boolean {
  109. if (data.type == Atomic.UI_EVENT_TYPE_KEY_UP) {
  110. // node deletion
  111. if (data.key == Atomic.KEY_DELETE || data.key == Atomic.KEY_BACKSPACE) {
  112. var selectedId = Number(this.hierList.rootList.selectedItemID);
  113. var node = this.scene.getNode(selectedId);
  114. if (node) {
  115. node.removeAllComponents();
  116. node.remove();
  117. }
  118. }
  119. } else if (data.type == Atomic.UI_EVENT_TYPE_POINTER_DOWN) {
  120. if (data.target == this.hierList.rootList) {
  121. var node = this.scene.getNode(Number(data.refid));
  122. if (node) {
  123. // set the widget's drag object
  124. var dragObject = new Atomic.UIDragObject(node, node.name.length ? "Node: " + node.name : "Node: (Anonymous)");
  125. this.hierList.rootList.dragObject = dragObject;
  126. }
  127. }
  128. } else if (data.type == Atomic.UI_EVENT_TYPE_CLICK) {
  129. if (this.menu.handleNodeContextMenu(data.target, data.refid)) {
  130. return true;
  131. }
  132. var id = data.target.id;
  133. if (id == "create popup") {
  134. var selectedId = Number(this.hierList.rootList.selectedItemID);
  135. var node = this.scene.getNode(selectedId);
  136. if (this.menu.handlePopupMenu(data.target, data.refid, node))
  137. return true;
  138. }
  139. // create
  140. if (id == "menu create") {
  141. if (!ToolCore.toolSystem.project) return;
  142. var src = MenuItemSources.getMenuItemSource("hierarchy create items");
  143. var menu = new Atomic.UIMenuWindow(data.target, "create popup");
  144. menu.show(src);
  145. return true;
  146. }
  147. if (id == "hierList_") {
  148. var list = <Atomic.UISelectList>data.target;
  149. var selectedId = Number(list.selectedItemID);
  150. var node = this.scene.getNode(selectedId);
  151. if (node) {
  152. this.sendEvent("EditorActiveNodeChange", { node: node });
  153. }
  154. return false;
  155. }
  156. } else if (data.type == Atomic.UI_EVENT_TYPE_RIGHT_POINTER_UP) {
  157. var id = data.target.id;
  158. var db = ToolCore.getAssetDatabase();
  159. var node: Atomic.Node;
  160. if (id == "hierList_")
  161. node = this.scene.getNode(Number(this.hierList.hoverItemID));
  162. else
  163. node = this.scene.getNode(Number(id));
  164. if (node) {
  165. this.menu.createNodeContextMenu(this, node, data.x, data.y);
  166. }
  167. }
  168. return false;
  169. }
  170. filterNode(node: Atomic.Node): boolean {
  171. if (!node) return false;
  172. if (node.name == "__atomic_sceneview3d_camera") return true;
  173. return false;
  174. }
  175. recursiveAddNode(parentID: number, node: Atomic.Node): number {
  176. if (this.filterNode(node))
  177. return;
  178. var name = node.name;
  179. if (!name.length)
  180. name = "(Anonymous)"
  181. var icon = "";
  182. if (node.isTemporary())
  183. icon = IconTemporary;
  184. var childItemID = this.hierList.addChildItem(parentID, name, icon, node.id.toString());
  185. if (node.getComponent("PrefabComponent")) {
  186. this.hierList.setItemTextSkin(node.id.toString(), "HierarchyPrefabText");
  187. }
  188. this.nodeIDToItemID[node.id] = childItemID;
  189. for (var i = 0; i < node.getNumChildren(false); i++) {
  190. this.recursiveAddNode(childItemID, node.getChildAtIndex(i));
  191. }
  192. return childItemID;
  193. }
  194. populate() {
  195. this.nodeIDToItemID = {};
  196. this.hierList.deleteAllItems();
  197. if (!this.scene)
  198. return;
  199. var parentID = this.hierList.addRootItem("Scene", "", this.scene.id.toString());
  200. this.nodeIDToItemID[this.scene.id] = parentID;
  201. for (var i = 0; i < this.scene.getNumChildren(false); i++) {
  202. this.recursiveAddNode(parentID, this.scene.getChildAtIndex(i));
  203. }
  204. this.hierList.rootList.value = 0;
  205. this.hierList.setExpanded(parentID, true);
  206. }
  207. handleDragEnded(ev: Atomic.DragEndedEvent) {
  208. var typeName = ev.dragObject.object.typeName;
  209. var dropNode: Atomic.Node = this.scene.getNode(Number(this.hierList.hoverItemID));
  210. if (!dropNode) return;
  211. if (typeName == "Node") {
  212. var dragNode = <Atomic.Node>ev.dragObject.object;
  213. if (dragNode.scene != this.scene) {
  214. return;
  215. }
  216. // can't drop on self
  217. if (dragNode == dropNode) {
  218. return;
  219. }
  220. // check if dropping on child of ourselves
  221. var parent = dropNode.parent;
  222. while (parent) {
  223. if (parent == dragNode) {
  224. return;
  225. }
  226. parent = parent.parent;
  227. }
  228. // move it
  229. dropNode.addChild(dragNode);
  230. } else if (typeName == "Asset") {
  231. var asset = <ToolCore.Asset>ev.dragObject.object;
  232. asset.instantiateNode(dropNode, asset.name);
  233. }
  234. }
  235. }
  236. export = HierarchyFrame;