/FlaxEditor/Content/Items/ContentFolder.cs

https://github.com/FlaxEngine/FlaxAPI · C# · 340 lines · 193 code · 58 blank · 89 comment · 48 complexity · ac471ce92c8a166f8e4f7b8a4cabb187 MD5 · raw file

  1. // Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using FlaxEditor.GUI.Drag;
  8. using FlaxEngine;
  9. using FlaxEngine.GUI;
  10. namespace FlaxEditor.Content
  11. {
  12. /// <summary>
  13. /// Types of content directories.
  14. /// </summary>
  15. public enum ContentFolderType
  16. {
  17. /// <summary>
  18. /// The directory with assets.
  19. /// </summary>
  20. Content,
  21. /// <summary>
  22. /// The directory with script source files.
  23. /// </summary>
  24. Source,
  25. /// <summary>
  26. /// The directory with Editor private files.
  27. /// </summary>
  28. Editor,
  29. /// <summary>
  30. /// The directory with Engine private files.
  31. /// </summary>
  32. Engine,
  33. /// <summary>
  34. /// The other type of directory.
  35. /// </summary>
  36. Other
  37. }
  38. /// <summary>
  39. /// Represents workspace directory item.
  40. /// </summary>
  41. public class ContentFolder : ContentItem
  42. {
  43. private DragItems _dragOverItems;
  44. private bool _validDragOver;
  45. /// <summary>
  46. /// Gets the type of the folder.
  47. /// </summary>
  48. public ContentFolderType FolderType { get; }
  49. /// <summary>
  50. /// Returns true if that folder can import/manage scripts.
  51. /// </summary>
  52. public bool CanHaveScripts => FolderType == ContentFolderType.Source;
  53. /// <summary>
  54. /// Returns true if that folder can import/manage assets.
  55. /// </summary>
  56. public bool CanHaveAssets => FolderType == ContentFolderType.Content || FolderType == ContentFolderType.Editor || FolderType == ContentFolderType.Engine;
  57. /// <summary>
  58. /// Returns true if that folder belongs to the project workspace.
  59. /// </summary>
  60. public bool IsProjectOnly => FolderType == ContentFolderType.Content || FolderType == ContentFolderType.Source;
  61. /// <summary>
  62. /// Returns true if that folder belongs to the Engine or Editor private files.
  63. /// </summary>
  64. public bool IsEnginePrivate => FolderType == ContentFolderType.Editor || FolderType == ContentFolderType.Engine;
  65. /// <summary>
  66. /// Gets the content node.
  67. /// </summary>
  68. public ContentTreeNode Node { get; }
  69. /// <summary>
  70. /// The subitems of this folder.
  71. /// </summary>
  72. public readonly List<ContentItem> Children = new List<ContentItem>();
  73. /// <summary>
  74. /// Initializes a new instance of the <see cref="ContentFolder"/> class.
  75. /// </summary>
  76. /// <param name="type">The folder type.</param>
  77. /// <param name="path">The path to the item.</param>
  78. /// <param name="node">The folder parent node.</param>
  79. internal ContentFolder(ContentFolderType type, string path, ContentTreeNode node)
  80. : base(path)
  81. {
  82. FolderType = type;
  83. Node = node;
  84. ShortName = System.IO.Path.GetFileName(path);
  85. }
  86. /// <summary>
  87. /// Tries to find child element with given path
  88. /// </summary>
  89. /// <param name="path">Element path to find</param>
  90. /// <returns>Found element of null</returns>
  91. public ContentItem FindChild(string path)
  92. {
  93. for (int i = 0; i < Children.Count; i++)
  94. {
  95. if (Children[i].Path == path)
  96. return Children[i];
  97. }
  98. return null;
  99. }
  100. /// <summary>
  101. /// Check if folder contains child element with given path
  102. /// </summary>
  103. /// <param name="path">Element path to find</param>
  104. /// <returns>True if contains that element, otherwise false</returns>
  105. public bool ContainsChild(string path)
  106. {
  107. return FindChild(path) != null;
  108. }
  109. /// <inheritdoc />
  110. public override ContentItemType ItemType => ContentItemType.Folder;
  111. /// <inheritdoc />
  112. public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
  113. /// <inheritdoc />
  114. public override bool CanRename => ParentFolder != null; // Deny rename action for root folders
  115. /// <inheritdoc />
  116. public override bool CanDrag => ParentFolder != null; // Deny rename action for root folders
  117. /// <inheritdoc />
  118. public override bool Exists => System.IO.Directory.Exists(Path);
  119. /// <inheritdoc />
  120. public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder64;
  121. /// <inheritdoc />
  122. internal override void UpdatePath(string value)
  123. {
  124. base.UpdatePath(value);
  125. ShortName = System.IO.Path.GetFileName(value);
  126. // Update node text
  127. Node.Text = ShortName;
  128. }
  129. private static long DirSize(DirectoryInfo dir)
  130. {
  131. long result = 0;
  132. var files = dir.GetFiles();
  133. for (int i = 0; i < files.Length; i++)
  134. result += files[i].Length;
  135. var dirs = dir.GetDirectories();
  136. for (int i = 0; i < dirs.Length; i++)
  137. result += DirSize(dirs[i]);
  138. return result;
  139. }
  140. /// <inheritdoc />
  141. protected override void UpdateTooltipText()
  142. {
  143. var sb = new StringBuilder();
  144. sb.Append("Size: ").Append(Utilities.Utils.FormatBytesCount((int)DirSize(new DirectoryInfo(Path)))).AppendLine();
  145. sb.Append("Path: ").Append(Path).AppendLine();
  146. TooltipText = sb.ToString();
  147. }
  148. /// <inheritdoc />
  149. protected override void OnParentFolderChanged()
  150. {
  151. // Update tree nodes structure
  152. Node.Parent = ParentFolder?.Node;
  153. base.OnParentFolderChanged();
  154. }
  155. /// <inheritdoc />
  156. public override ContentItem Find(string path)
  157. {
  158. // TODO: split name into parts and check each going tree structure level down - make it faster
  159. if (Path == path)
  160. return this;
  161. for (int i = 0; i < Children.Count; i++)
  162. {
  163. var result = Children[i].Find(path);
  164. if (result != null)
  165. return result;
  166. }
  167. return null;
  168. }
  169. /// <inheritdoc />
  170. public override bool Find(ContentItem item)
  171. {
  172. if (item == this)
  173. return true;
  174. for (int i = 0; i < Children.Count; i++)
  175. {
  176. if (Children[i].Find(item))
  177. return true;
  178. }
  179. return false;
  180. }
  181. /// <inheritdoc />
  182. public override ContentItem Find(Guid id)
  183. {
  184. for (int i = 0; i < Children.Count; i++)
  185. {
  186. var result = Children[i].Find(id);
  187. if (result != null)
  188. return result;
  189. }
  190. return null;
  191. }
  192. /// <inheritdoc />
  193. public override ScriptItem FindScriptWitScriptName(string scriptName)
  194. {
  195. for (int i = 0; i < Children.Count; i++)
  196. {
  197. var result = Children[i].FindScriptWitScriptName(scriptName);
  198. if (result != null)
  199. return result;
  200. }
  201. return null;
  202. }
  203. /// <inheritdoc />
  204. public override int Compare(Control other)
  205. {
  206. if (other is ContentItem otherItem)
  207. {
  208. if (!otherItem.IsFolder)
  209. return -1;
  210. return string.Compare(ShortName, otherItem.ShortName, StringComparison.InvariantCulture);
  211. }
  212. return base.Compare(other);
  213. }
  214. /// <inheritdoc />
  215. public override void Draw()
  216. {
  217. base.Draw();
  218. // Check if drag is over
  219. if (IsDragOver && _validDragOver)
  220. Render2D.FillRectangle(new Rectangle(Vector2.Zero, Size), Style.Current.BackgroundSelected * 0.6f);
  221. }
  222. private bool ValidateDragItem(ContentItem item)
  223. {
  224. // Reject itself and any parent
  225. return item != this && !item.Find(this);
  226. }
  227. /// <inheritdoc />
  228. public override DragDropEffect OnDragEnter(ref Vector2 location, DragData data)
  229. {
  230. base.OnDragEnter(ref location, data);
  231. // Check if drop file(s)
  232. if (data is DragDataFiles)
  233. {
  234. _validDragOver = true;
  235. return DragDropEffect.Copy;
  236. }
  237. // Check if drop asset(s)
  238. if (_dragOverItems == null)
  239. _dragOverItems = new DragItems(ValidateDragItem);
  240. _dragOverItems.OnDragEnter(data);
  241. _validDragOver = _dragOverItems.HasValidDrag;
  242. return _dragOverItems.Effect;
  243. }
  244. /// <inheritdoc />
  245. public override DragDropEffect OnDragMove(ref Vector2 location, DragData data)
  246. {
  247. base.OnDragMove(ref location, data);
  248. if (data is DragDataFiles)
  249. return DragDropEffect.Copy;
  250. return _dragOverItems.Effect;
  251. }
  252. /// <inheritdoc />
  253. public override DragDropEffect OnDragDrop(ref Vector2 location, DragData data)
  254. {
  255. var result = base.OnDragDrop(ref location, data);
  256. // Check if drop file(s)
  257. if (data is DragDataFiles files)
  258. {
  259. // Import files
  260. Editor.Instance.ContentImporting.Import(files.Files, this);
  261. result = DragDropEffect.Copy;
  262. }
  263. else if (_dragOverItems.HasValidDrag)
  264. {
  265. // Move items
  266. Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, this);
  267. result = DragDropEffect.Move;
  268. }
  269. // Clear cache
  270. _dragOverItems?.OnDragDrop();
  271. _validDragOver = false;
  272. return result;
  273. }
  274. /// <inheritdoc />
  275. public override void OnDragLeave()
  276. {
  277. _dragOverItems?.OnDragLeave();
  278. _validDragOver = false;
  279. base.OnDragLeave();
  280. }
  281. }
  282. }