EditorNodeWindow.as 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Urho3D editor attribute inspector window handling
  2. #include "Scripts/Editor/AttributeEditor.as"
  3. Window@ nodeWindow;
  4. UIElement@ componentParentContainer;
  5. XMLFile@ componentXMLResource;
  6. bool applyMaterialList = true;
  7. const String STRIKED_OUT = "——"; // Two unicode EM DASH (U+2014)
  8. void AddComponentContainer()
  9. {
  10. componentParentContainer.LoadXML(componentXMLResource, uiStyle);
  11. }
  12. void DeleteAllComponentContainers()
  13. {
  14. componentParentContainer.RemoveAllChildren();
  15. }
  16. UIElement@ GetComponentContainer(uint index)
  17. {
  18. return componentParentContainer.children[index];
  19. }
  20. void CreateNodeWindow()
  21. {
  22. if (nodeWindow !is null)
  23. return;
  24. InitResourcePicker();
  25. InitVectorStructs();
  26. nodeWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorNodeWindow.xml"));
  27. componentXMLResource = cache.GetResource("XMLFile", "UI/EditorComponent.xml");
  28. componentParentContainer = nodeWindow.GetChild("ComponentParentContainer", true);
  29. AddComponentContainer();
  30. ui.root.AddChild(nodeWindow);
  31. int height = Min(ui.root.height - 60, 500);
  32. nodeWindow.SetSize(300, height);
  33. nodeWindow.SetPosition(ui.root.width - 20 - nodeWindow.width, 40);
  34. nodeWindow.opacity = uiMaxOpacity;
  35. nodeWindow.BringToFront();
  36. UpdateNodeWindow();
  37. SubscribeToEvent(nodeWindow.GetChild("CloseButton", true), "Released", "HideNodeWindow");
  38. SubscribeToEvent(nodeWindow.GetChild("NewVarDropDown", true), "ItemSelected", "CreateNewVariable");
  39. SubscribeToEvent(nodeWindow.GetChild("DeleteVarButton", true), "Released", "DeleteVariable");
  40. }
  41. void HideNodeWindow()
  42. {
  43. nodeWindow.visible = false;
  44. }
  45. void ShowNodeWindow()
  46. {
  47. nodeWindow.visible = true;
  48. nodeWindow.BringToFront();
  49. }
  50. void AppendID(String&inout localIds, String&inout ids, Node@ node)
  51. {
  52. if (node.id >= FIRST_LOCAL_ID)
  53. localIds += " " + String(node.id - FIRST_LOCAL_ID);
  54. else
  55. ids += " " + String(node.id);
  56. }
  57. void UpdateNodeWindow()
  58. {
  59. // If a resource pick was in progress, it cannot be completed now, as component was changed
  60. PickResourceCanceled();
  61. Text@ nodeTitle = nodeWindow.GetChild("NodeTitle", true);
  62. if (editNodes.length == 0)
  63. nodeTitle.text = "No node";
  64. else if (editNode !is null)
  65. {
  66. String idStr;
  67. if (editNode.id >= FIRST_LOCAL_ID)
  68. idStr = " Local ID " + String(editNode.id - FIRST_LOCAL_ID);
  69. else
  70. idStr = " ID " + String(editNode.id);
  71. nodeTitle.text = editNode.typeName + idStr;
  72. }
  73. else
  74. nodeTitle.text = editNodes[0].typeName + " ID " + STRIKED_OUT + " (" + editNodes.length + "x)";
  75. UpdateAttributes(true);
  76. }
  77. Array<Serializable@> ToSerializableArray(Array<Node@> nodes)
  78. {
  79. Array<Serializable@> serializables;
  80. for (uint i = 0; i < nodes.length; ++i)
  81. serializables.Push(nodes[i]);
  82. return serializables;
  83. }
  84. void UpdateAttributes(bool fullUpdate)
  85. {
  86. if (nodeWindow !is null)
  87. {
  88. UpdateAttributes(ToSerializableArray(editNodes), nodeWindow.GetChild("NodeAttributeList", true), fullUpdate);
  89. if (fullUpdate)
  90. DeleteAllComponentContainers();
  91. if (editComponents.empty)
  92. {
  93. if (componentParentContainer.numChildren == 0)
  94. AddComponentContainer();
  95. Text@ componentTitle = GetComponentContainer(0).GetChild("ComponentTitle");
  96. if (selectedComponents.length <= 1)
  97. componentTitle.text = "No component";
  98. else
  99. componentTitle.text = selectedComponents.length + " components";
  100. }
  101. else
  102. {
  103. uint numEditableComponents = editComponents.length / numEditableComponentsPerNode;
  104. String multiplierText;
  105. if (numEditableComponents > 1)
  106. multiplierText = " (" + numEditableComponents + "x)";
  107. for (uint j = 0; j < numEditableComponentsPerNode; ++j)
  108. {
  109. if (j >= componentParentContainer.numChildren)
  110. AddComponentContainer();
  111. Text@ componentTitle = GetComponentContainer(j).GetChild("ComponentTitle");
  112. componentTitle.text = GetComponentTitle(editComponents[j * numEditableComponents]) + multiplierText;
  113. Array<Serializable@> components;
  114. for (uint i = 0; i < numEditableComponents; ++i)
  115. components.Push(editComponents[j * numEditableComponents + i]);
  116. UpdateAttributes(components, GetComponentContainer(j).GetChild("ComponentAttributeList"), fullUpdate);
  117. }
  118. }
  119. }
  120. }
  121. void UpdateNodeAttributes()
  122. {
  123. if (nodeWindow !is null)
  124. {
  125. UpdateAttributes(ToSerializableArray(editNodes), nodeWindow.GetChild("NodeAttributeList", true), false);
  126. }
  127. }
  128. void PostEditAttribute(Array<Serializable@>@ serializables, uint index)
  129. {
  130. // If a StaticModel/AnimatedModel/Skybox model was changed, apply a possibly different material list
  131. if (applyMaterialList && serializables[0].attributeInfos[index].name == "Model")
  132. {
  133. for (uint i = 0; i < serializables.length; ++i)
  134. {
  135. StaticModel@ staticModel = cast<StaticModel>(serializables[i]);
  136. if (staticModel !is null)
  137. ApplyMaterialList(staticModel);
  138. }
  139. }
  140. }
  141. void SetAttributeEditorID(UIElement@ attrEdit, Array<Serializable@>@ serializables)
  142. {
  143. // All target serializables must be either nodes or components, so can check the first for the type
  144. Node@ node = cast<Node>(serializables[0]);
  145. Array<Variant> ids;
  146. if (node !is null)
  147. {
  148. for (uint i = 0; i < serializables.length; ++i)
  149. ids.Push(Variant(cast<Node>(serializables[i]).id));
  150. attrEdit.vars["NodeIDs"] = ids;
  151. }
  152. else
  153. {
  154. for (uint i = 0; i < serializables.length; ++i)
  155. ids.Push(Variant(cast<Component>(serializables[i]).id));
  156. attrEdit.vars["ComponentIDs"] = ids;
  157. }
  158. }
  159. Array<Serializable@>@ GetAttributeEditorTargets(UIElement@ attrEdit)
  160. {
  161. Array<Serializable@> ret;
  162. if (attrEdit.vars.Contains("NodeIDs"))
  163. {
  164. Array<Variant>@ ids = attrEdit.vars["NodeIDs"].GetVariantVector();
  165. for (uint i = 0; i < ids.length; ++i)
  166. {
  167. Node@ node = editorScene.GetNode(ids[i].GetUInt());
  168. if (node !is null)
  169. ret.Push(node);
  170. }
  171. }
  172. if (attrEdit.vars.Contains("ComponentIDs"))
  173. {
  174. Array<Variant>@ ids = attrEdit.vars["ComponentIDs"].GetVariantVector();
  175. for (uint i = 0; i < ids.length; ++i)
  176. {
  177. Component@ component = editorScene.GetComponent(ids[i].GetUInt());
  178. if (component !is null)
  179. ret.Push(component);
  180. }
  181. }
  182. return ret;
  183. }
  184. void CreateNewVariable(StringHash eventType, VariantMap& eventData)
  185. {
  186. if (editNodes.length == 0)
  187. return;
  188. DropDownList@ dropDown = eventData["Element"].GetUIElement();
  189. LineEdit@ nameEdit = nodeWindow.GetChild("VarNameEdit", true);
  190. String sanitatedVarName = nameEdit.text.Trimmed().Replaced(";", "");
  191. if (sanitatedVarName.empty)
  192. return;
  193. editorScene.RegisterVar(sanitatedVarName);
  194. Variant newValue;
  195. switch (dropDown.selection)
  196. {
  197. case 0:
  198. newValue = int(0);
  199. break;
  200. case 1:
  201. newValue = false;
  202. break;
  203. case 2:
  204. newValue = float(0.0);
  205. break;
  206. case 3:
  207. newValue = String();
  208. break;
  209. case 4:
  210. newValue = Vector3();
  211. break;
  212. case 5:
  213. newValue = Color();
  214. break;
  215. }
  216. // If we overwrite an existing variable, must recreate the editor(s) for the correct type
  217. bool overwrite = false;
  218. for (uint i = 0; i < editNodes.length; ++i)
  219. {
  220. overwrite = overwrite || editNodes[i].vars.Contains(sanitatedVarName);
  221. editNodes[i].vars[sanitatedVarName] = newValue;
  222. }
  223. UpdateAttributes(overwrite);
  224. }
  225. void DeleteVariable(StringHash eventType, VariantMap& eventData)
  226. {
  227. if (editNodes.length == 0)
  228. return;
  229. LineEdit@ nameEdit = nodeWindow.GetChild("VarNameEdit", true);
  230. String sanitatedVarName = nameEdit.text.Trimmed().Replaced(";", "");
  231. if (sanitatedVarName.empty)
  232. return;
  233. bool erased = false;
  234. for (uint i = 0; i < editNodes.length; ++i)
  235. {
  236. // \todo Should first check whether var in question is editable
  237. erased = editNodes[i].vars.Erase(sanitatedVarName) || erased;
  238. }
  239. if (erased)
  240. UpdateAttributes(false);
  241. }