// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Text; using FlaxEditor.GUI.Drag; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Content { /// /// Types of content directories. /// [HideInEditor] public enum ContentFolderType { /// /// The directory with assets. /// Content, /// /// The directory with source files. /// Source, /// /// The other type of directory. /// Other, } /// /// Represents workspace directory item. /// [HideInEditor] public class ContentFolder : ContentItem { private DragItems _dragOverItems; private bool _validDragOver; /// /// Gets the type of the folder. /// public ContentFolderType FolderType { get; } /// /// Returns true if that folder can import/manage scripts. /// public bool CanHaveScripts => FolderType == ContentFolderType.Source; /// /// Returns true if that folder can import/manage assets. /// public bool CanHaveAssets => FolderType == ContentFolderType.Content; /// /// Gets the content node. /// public ContentTreeNode Node { get; } /// /// The subitems of this folder. /// public readonly List Children = new List(); /// /// Initializes a new instance of the class. /// /// The folder type. /// The path to the item. /// The folder parent node. internal ContentFolder(ContentFolderType type, string path, ContentTreeNode node) : base(path) { FolderType = type; Node = node; ShortName = System.IO.Path.GetFileName(path); } /// /// Tries to find child element with given path /// /// Element path to find /// Found element of null public ContentItem FindChild(string path) { for (int i = 0; i < Children.Count; i++) { if (Children[i].Path == path) return Children[i]; } return null; } /// /// Check if folder contains child element with given path /// /// Element path to find /// True if contains that element, otherwise false public bool ContainsChild(string path) { return FindChild(path) != null; } /// public override ContentItemType ItemType => ContentItemType.Folder; /// public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other; /// public override bool CanRename { get { var hasParentFolder = ParentFolder != null; var isContentFolder = Node is MainContentTreeNode; return hasParentFolder && !isContentFolder; } } /// public override bool CanDrag => ParentFolder != null; // Deny rename action for root folders /// public override bool Exists => Directory.Exists(Path); /// public override string TypeDescription => "Folder"; /// public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder128; /// internal override void UpdatePath(string value) { base.UpdatePath(value); ShortName = System.IO.Path.GetFileName(value); // Update node text Node.Text = ShortName; } /// protected override void OnBuildTooltipText(StringBuilder sb) { sb.Append("Type: ").Append(TypeDescription).AppendLine(); sb.Append("Path: ").Append(Utilities.Utils.GetAssetNamePathWithExt(Path)).AppendLine(); } /// protected override void OnParentFolderChanged() { // Update tree nodes structure Node.Parent = ParentFolder?.Node; base.OnParentFolderChanged(); } /// public override ContentItem Find(string path) { // TODO: split name into parts and check each going tree structure level down - make it faster if (Path == path) return this; for (int i = 0; i < Children.Count; i++) { var result = Children[i].Find(path); if (result != null) return result; } return null; } /// public override bool Find(ContentItem item) { if (item == this) return true; for (int i = 0; i < Children.Count; i++) { if (Children[i].Find(item)) return true; } return false; } /// public override ContentItem Find(Guid id) { for (int i = 0; i < Children.Count; i++) { var result = Children[i].Find(id); if (result != null) return result; } return null; } /// public override ScriptItem FindScriptWitScriptName(string scriptName) { for (int i = 0; i < Children.Count; i++) { var result = Children[i].FindScriptWitScriptName(scriptName); if (result != null) return result; } return null; } /// public override int Compare(Control other) { if (other is ContentItem otherItem) { if (!otherItem.IsFolder) return -1; return string.Compare(ShortName, otherItem.ShortName, StringComparison.InvariantCulture); } return base.Compare(other); } /// public override void Draw() { base.Draw(); // Check if drag is over if (IsDragOver && _validDragOver) Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), Style.Current.BackgroundSelected * 0.6f); } private bool ValidateDragItem(ContentItem item) { // Reject itself and any parent return item != this && !item.Find(this); } /// public override DragDropEffect OnDragEnter(ref Float2 location, DragData data) { base.OnDragEnter(ref location, data); // Check if drop file(s) if (data is DragDataFiles) { _validDragOver = true; return DragDropEffect.Copy; } // Check if drop asset(s) if (_dragOverItems == null) _dragOverItems = new DragItems(ValidateDragItem); _dragOverItems.OnDragEnter(data); _validDragOver = _dragOverItems.HasValidDrag; return _dragOverItems.Effect; } /// public override DragDropEffect OnDragMove(ref Float2 location, DragData data) { base.OnDragMove(ref location, data); if (data is DragDataFiles) return DragDropEffect.Copy; return _dragOverItems.Effect; } /// public override DragDropEffect OnDragDrop(ref Float2 location, DragData data) { var result = base.OnDragDrop(ref location, data); // Check if drop file(s) if (data is DragDataFiles files) { // Import files Editor.Instance.ContentImporting.Import(files.Files, this); result = DragDropEffect.Copy; } else if (_dragOverItems.HasValidDrag) { // Move items Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, this); result = DragDropEffect.Move; } // Clear cache _dragOverItems?.OnDragDrop(); _validDragOver = false; return result; } /// public override void OnDragLeave() { _dragOverItems?.OnDragLeave(); _validDragOver = false; base.OnDragLeave(); } } }