// 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();
}
}
}