You're breathtaking!
This commit is contained in:
126
Source/Editor/Content/Items/AssetItem.cs
Normal file
126
Source/Editor/Content/Items/AssetItem.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Asset item object.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentItem" />
|
||||
[HideInEditor]
|
||||
public abstract class AssetItem : ContentItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the asset unique identifier.
|
||||
/// </summary>
|
||||
public Guid ID { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset type identifier.
|
||||
/// </summary>
|
||||
public string TypeName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The asset path.</param>
|
||||
/// <param name="typeName">The asset type name.</param>
|
||||
/// <param name="id">The asset identifier.</param>
|
||||
protected AssetItem(string path, string typeName, ref Guid id)
|
||||
: base(path)
|
||||
{
|
||||
TypeName = typeName;
|
||||
ID = id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateTooltipText()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
OnBuildTooltipText(sb);
|
||||
TooltipText = sb.ToString();
|
||||
}
|
||||
|
||||
private sealed class TooltipDoubleClickHook : Control
|
||||
{
|
||||
public AssetItem Item;
|
||||
|
||||
public TooltipDoubleClickHook()
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll;
|
||||
Offsets = Margin.Zero;
|
||||
}
|
||||
|
||||
public override bool OnMouseDoubleClick(Vector2 location, MouseButton button)
|
||||
{
|
||||
return Item.OnMouseDoubleClick(Item.ScreenToClient(ClientToScreen(location)), button);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnTooltipShown(Tooltip tooltip)
|
||||
{
|
||||
base.OnTooltipShown(tooltip);
|
||||
|
||||
// Inject the hook control for the double-click event (if user double-clicks on tooltip over the asset item it will open that item - helps on small screens)
|
||||
var hook = tooltip.GetChild<TooltipDoubleClickHook>();
|
||||
if (hook == null)
|
||||
hook = tooltip.AddChild<TooltipDoubleClickHook>();
|
||||
hook.Item = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when building tooltip text.
|
||||
/// </summary>
|
||||
/// <param name="sb">The String Builder.</param>
|
||||
protected virtual void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
sb.Append("Type: ").Append(TypeName).AppendLine();
|
||||
sb.Append("Size: ").Append(Utilities.Utils.FormatBytesCount((int)new FileInfo(Path).Length)).AppendLine();
|
||||
sb.Append("Path: ").Append(Path).AppendLine();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Asset;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether asset is of the specified type (included inheritance checks).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to check.</typeparam>
|
||||
/// <returns><c>true</c> if asset is of the specified type (including inherited types); otherwise, <c>false</c>.</returns>
|
||||
public bool IsOfType<T>()
|
||||
{
|
||||
return IsOfType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether asset is of the specified type (included inheritance checks).
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check.</param>
|
||||
/// <returns><c>true</c> if asset is of the specified type (including inherited types); otherwise, <c>false</c>.</returns>
|
||||
public virtual bool IsOfType(Type type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItem Find(Guid id)
|
||||
{
|
||||
return id == ID ? this : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Path + ":" + ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
181
Source/Editor/Content/Items/BinaryAssetItem.cs
Normal file
181
Source/Editor/Content/Items/BinaryAssetItem.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents binary asset item.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.AssetItem" />
|
||||
public class BinaryAssetItem : AssetItem
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the asset (the same as <see cref="AssetItem.TypeName"/> but cached as type reference).
|
||||
/// </summary>
|
||||
public readonly Type Type;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BinaryAssetItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The asset path.</param>
|
||||
/// <param name="id">The asset identifier.</param>
|
||||
/// <param name="typeName">The asset type name identifier.</param>
|
||||
/// <param name="type">The asset type.</param>
|
||||
/// <param name="searchFilter">The asset type search filter type.</param>
|
||||
public BinaryAssetItem(string path, ref Guid id, string typeName, Type type, ContentItemSearchFilter searchFilter)
|
||||
: base(path, typeName, ref id)
|
||||
{
|
||||
Type = type;
|
||||
SearchFilter = searchFilter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset import path.
|
||||
/// </summary>
|
||||
/// <param name="importPath">The import path.</param>
|
||||
/// <returns>True if fails, otherwise false.</returns>
|
||||
public bool GetImportPath(out string importPath)
|
||||
{
|
||||
// TODO: add internal call to content backend with fast import asset metadata gather (without asset loading)
|
||||
|
||||
var asset = FlaxEngine.Content.Load<BinaryAsset>(ID, 100);
|
||||
if (asset)
|
||||
{
|
||||
// Get meta from loaded asset
|
||||
importPath = asset.ImportPath;
|
||||
return string.IsNullOrEmpty(importPath);
|
||||
}
|
||||
|
||||
importPath = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void OnReimport(ref Guid id)
|
||||
{
|
||||
ID = id;
|
||||
OnReimport();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsOfType(Type type)
|
||||
{
|
||||
return type.IsAssignableFrom(Type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="TextureBase"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class TextureAssetItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public TextureAssetItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Texture)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
base.OnBuildTooltipText(sb);
|
||||
|
||||
var asset = FlaxEngine.Content.Load<TextureBase>(ID, 100);
|
||||
if (asset)
|
||||
{
|
||||
sb.Append("Format: ").Append(asset.Format).AppendLine();
|
||||
sb.Append("Size: ").Append(asset.Width).Append('x').Append(asset.Height);
|
||||
if (asset.ArraySize != 1)
|
||||
sb.Append('[').Append(asset.ArraySize).Append(']');
|
||||
sb.AppendLine();
|
||||
sb.Append("Mip Levels: ").Append(asset.MipLevels).AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="Model"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class ModelAssetItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ModelAssetItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
base.OnBuildTooltipText(sb);
|
||||
|
||||
var asset = FlaxEngine.Content.Load<Model>(ID, 100);
|
||||
if (asset)
|
||||
{
|
||||
var lods = asset.LODs;
|
||||
int triangleCount = 0, vertexCount = 0;
|
||||
for (int lodIndex = 0; lodIndex < lods.Length; lodIndex++)
|
||||
{
|
||||
var lod = lods[lodIndex];
|
||||
for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++)
|
||||
{
|
||||
var mesh = lod.Meshes[meshIndex];
|
||||
triangleCount += mesh.TriangleCount;
|
||||
vertexCount += mesh.VertexCount;
|
||||
}
|
||||
}
|
||||
sb.Append("LODs: ").Append(lods.Length).AppendLine();
|
||||
sb.Append("Triangles: ").Append(triangleCount.ToString("N0")).AppendLine();
|
||||
sb.Append("Vertices: ").Append(vertexCount.ToString("N0")).AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SkinnedModel"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class SkinnedModelAssetItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public SkinnedModelAssetItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
base.OnBuildTooltipText(sb);
|
||||
|
||||
var asset = FlaxEngine.Content.Load<SkinnedModel>(ID, 100);
|
||||
if (asset)
|
||||
{
|
||||
var lods = asset.LODs;
|
||||
int triangleCount = 0, vertexCount = 0;
|
||||
for (int lodIndex = 0; lodIndex < lods.Length; lodIndex++)
|
||||
{
|
||||
var lod = lods[lodIndex];
|
||||
for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++)
|
||||
{
|
||||
var mesh = lod.Meshes[meshIndex];
|
||||
triangleCount += mesh.TriangleCount;
|
||||
vertexCount += mesh.VertexCount;
|
||||
}
|
||||
}
|
||||
sb.Append("LODs: ").Append(lods.Length).AppendLine();
|
||||
sb.Append("Triangles: ").Append(triangleCount.ToString("N0")).AppendLine();
|
||||
sb.Append("Vertices: ").Append(vertexCount.ToString("N0")).AppendLine();
|
||||
sb.Append("Skeleton Nodes: ").Append(asset.Nodes.Length).AppendLine();
|
||||
sb.Append("Blend Shapes: ").Append(asset.BlendShapes.Length).AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Source/Editor/Content/Items/CSharpScriptItem.cs
Normal file
25
Source/Editor/Content/Items/CSharpScriptItem.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains C# script file with source code.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ScriptItem" />
|
||||
public class CSharpScriptItem : ScriptItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CSharpScriptItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
public CSharpScriptItem(string path)
|
||||
: base(path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript64;
|
||||
}
|
||||
}
|
||||
305
Source/Editor/Content/Items/ContentFolder.cs
Normal file
305
Source/Editor/Content/Items/ContentFolder.cs
Normal file
@@ -0,0 +1,305 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Types of content directories.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ContentFolderType
|
||||
{
|
||||
/// <summary>
|
||||
/// The directory with assets.
|
||||
/// </summary>
|
||||
Content,
|
||||
|
||||
/// <summary>
|
||||
/// The directory with source files.
|
||||
/// </summary>
|
||||
Source,
|
||||
|
||||
/// <summary>
|
||||
/// The other type of directory.
|
||||
/// </summary>
|
||||
Other,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents workspace directory item.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public class ContentFolder : ContentItem
|
||||
{
|
||||
private DragItems _dragOverItems;
|
||||
private bool _validDragOver;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the folder.
|
||||
/// </summary>
|
||||
public ContentFolderType FolderType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if that folder can import/manage scripts.
|
||||
/// </summary>
|
||||
public bool CanHaveScripts => FolderType == ContentFolderType.Source;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if that folder can import/manage assets.
|
||||
/// </summary>
|
||||
public bool CanHaveAssets => FolderType == ContentFolderType.Content;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content node.
|
||||
/// </summary>
|
||||
public ContentTreeNode Node { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The subitems of this folder.
|
||||
/// </summary>
|
||||
public readonly List<ContentItem> Children = new List<ContentItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentFolder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The folder type.</param>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
/// <param name="node">The folder parent node.</param>
|
||||
internal ContentFolder(ContentFolderType type, string path, ContentTreeNode node)
|
||||
: base(path)
|
||||
{
|
||||
FolderType = type;
|
||||
Node = node;
|
||||
ShortName = System.IO.Path.GetFileName(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find child element with given path
|
||||
/// </summary>
|
||||
/// <param name="path">Element path to find</param>
|
||||
/// <returns>Found element of null</returns>
|
||||
public ContentItem FindChild(string path)
|
||||
{
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (Children[i].Path == path)
|
||||
return Children[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if folder contains child element with given path
|
||||
/// </summary>
|
||||
/// <param name="path">Element path to find</param>
|
||||
/// <returns>True if contains that element, otherwise false</returns>
|
||||
public bool ContainsChild(string path)
|
||||
{
|
||||
return FindChild(path) != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Folder;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRename => ParentFolder != null; // Deny rename action for root folders
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanDrag => ParentFolder != null; // Deny rename action for root folders
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Exists => Directory.Exists(Path);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder64;
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override void UpdatePath(string value)
|
||||
{
|
||||
base.UpdatePath(value);
|
||||
|
||||
ShortName = System.IO.Path.GetFileName(value);
|
||||
|
||||
// Update node text
|
||||
Node.Text = ShortName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateTooltipText()
|
||||
{
|
||||
TooltipText = Path;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnParentFolderChanged()
|
||||
{
|
||||
// Update tree nodes structure
|
||||
Node.Parent = ParentFolder?.Node;
|
||||
|
||||
base.OnParentFolderChanged();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
// Check if drag is over
|
||||
if (IsDragOver && _validDragOver)
|
||||
Render2D.FillRectangle(new Rectangle(Vector2.Zero, Size), Style.Current.BackgroundSelected * 0.6f);
|
||||
}
|
||||
|
||||
private bool ValidateDragItem(ContentItem item)
|
||||
{
|
||||
// Reject itself and any parent
|
||||
return item != this && !item.Find(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragEnter(ref Vector2 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragMove(ref Vector2 location, DragData data)
|
||||
{
|
||||
base.OnDragMove(ref location, data);
|
||||
|
||||
if (data is DragDataFiles)
|
||||
return DragDropEffect.Copy;
|
||||
return _dragOverItems.Effect;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragDrop(ref Vector2 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragOverItems?.OnDragLeave();
|
||||
_validDragOver = false;
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
}
|
||||
}
|
||||
772
Source/Editor/Content/Items/ContentItem.cs
Normal file
772
Source/Editor/Content/Items/ContentItem.cs
Normal file
@@ -0,0 +1,772 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Content.GUI;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item types.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ContentItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The binary or text asset.
|
||||
/// </summary>
|
||||
Asset,
|
||||
|
||||
/// <summary>
|
||||
/// The directory.
|
||||
/// </summary>
|
||||
Folder,
|
||||
|
||||
/// <summary>
|
||||
/// The script file.
|
||||
/// </summary>
|
||||
Script,
|
||||
|
||||
/// <summary>
|
||||
/// The scene file.
|
||||
/// </summary>
|
||||
Scene,
|
||||
|
||||
/// <summary>
|
||||
/// The other type.
|
||||
/// </summary>
|
||||
Other,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Content item filter types used for searching.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ContentItemSearchFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// The model.
|
||||
/// </summary>
|
||||
Model,
|
||||
|
||||
/// <summary>
|
||||
/// The skinned model.
|
||||
/// </summary>
|
||||
SkinnedModel,
|
||||
|
||||
/// <summary>
|
||||
/// The material.
|
||||
/// </summary>
|
||||
Material,
|
||||
|
||||
/// <summary>
|
||||
/// The texture.
|
||||
/// </summary>
|
||||
Texture,
|
||||
|
||||
/// <summary>
|
||||
/// The scene.
|
||||
/// </summary>
|
||||
Scene,
|
||||
|
||||
/// <summary>
|
||||
/// The prefab.
|
||||
/// </summary>
|
||||
Prefab,
|
||||
|
||||
/// <summary>
|
||||
/// The script.
|
||||
/// </summary>
|
||||
Script,
|
||||
|
||||
/// <summary>
|
||||
/// The audio.
|
||||
/// </summary>
|
||||
Audio,
|
||||
|
||||
/// <summary>
|
||||
/// The animation.
|
||||
/// </summary>
|
||||
Animation,
|
||||
|
||||
/// <summary>
|
||||
/// The json.
|
||||
/// </summary>
|
||||
Json,
|
||||
|
||||
/// <summary>
|
||||
/// The particles.
|
||||
/// </summary>
|
||||
Particles,
|
||||
|
||||
/// <summary>
|
||||
/// The shader source files.
|
||||
/// </summary>
|
||||
Shader,
|
||||
|
||||
/// <summary>
|
||||
/// The other.
|
||||
/// </summary>
|
||||
Other,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for objects that can reference the content items in order to receive events from them.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public interface IContentItemOwner
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when referenced item gets deleted (asset unloaded, file deleted, etc.).
|
||||
/// Item should not be used after that.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
void OnItemDeleted(ContentItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Called when referenced item gets renamed (filename change, path change, etc.)
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
void OnItemRenamed(ContentItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Called when item gets reimported or reloaded.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
void OnItemReimported(ContentItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Called when referenced item gets disposed (editor closing, database internal changes, etc.).
|
||||
/// Item should not be used after that.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
void OnItemDispose(ContentItem item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all content items.
|
||||
/// Item parent GUI control is always <see cref="ContentView"/> or null if not in a view.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.Control" />
|
||||
[HideInEditor]
|
||||
public abstract class ContentItem : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The default margin size.
|
||||
/// </summary>
|
||||
public const int DefaultMarginSize = 4;
|
||||
|
||||
/// <summary>
|
||||
/// The default text height.
|
||||
/// </summary>
|
||||
public const int DefaultTextHeight = 42;
|
||||
|
||||
/// <summary>
|
||||
/// The default thumbnail size.
|
||||
/// </summary>
|
||||
public const int DefaultThumbnailSize = PreviewsCache.AssetIconSize;
|
||||
|
||||
/// <summary>
|
||||
/// The default width.
|
||||
/// </summary>
|
||||
public const int DefaultWidth = (DefaultThumbnailSize + 2 * DefaultMarginSize);
|
||||
|
||||
/// <summary>
|
||||
/// The default height.
|
||||
/// </summary>
|
||||
public const int DefaultHeight = (DefaultThumbnailSize + 2 * DefaultMarginSize + DefaultTextHeight);
|
||||
|
||||
private ContentFolder _parentFolder;
|
||||
|
||||
private bool _isMouseDown;
|
||||
private Vector2 _mouseDownStartPos;
|
||||
private readonly List<IContentItemOwner> _references = new List<IContentItemOwner>(4);
|
||||
|
||||
private SpriteHandle _thumbnail;
|
||||
private SpriteHandle _shadowIcon;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the item.
|
||||
/// </summary>
|
||||
public abstract ContentItemType ItemType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the item searching filter to use.
|
||||
/// </summary>
|
||||
public abstract ContentItemSearchFilter SearchFilter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is asset.
|
||||
/// </summary>
|
||||
public bool IsAsset => ItemType == ContentItemType.Asset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is folder.
|
||||
/// </summary>
|
||||
public bool IsFolder => ItemType == ContentItemType.Folder;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance can have children.
|
||||
/// </summary>
|
||||
public bool CanHaveChildren => ItemType == ContentItemType.Folder;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this item can be renamed.
|
||||
/// </summary>
|
||||
public virtual bool CanRename => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this item can be dragged and dropped.
|
||||
/// </summary>
|
||||
public virtual bool CanDrag => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="ContentItem"/> exists on drive.
|
||||
/// </summary>
|
||||
public virtual bool Exists => System.IO.File.Exists(Path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent folder.
|
||||
/// </summary>
|
||||
public ContentFolder ParentFolder
|
||||
{
|
||||
get => _parentFolder;
|
||||
set
|
||||
{
|
||||
if (_parentFolder == value)
|
||||
return;
|
||||
|
||||
// Remove from old
|
||||
_parentFolder?.Children.Remove(this);
|
||||
|
||||
// Link
|
||||
_parentFolder = value;
|
||||
|
||||
// Add to new
|
||||
_parentFolder?.Children.Add(this);
|
||||
|
||||
OnParentFolderChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the item.
|
||||
/// </summary>
|
||||
public string Path { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item file name (filename with extension).
|
||||
/// </summary>
|
||||
public string FileName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item short name (filename without extension).
|
||||
/// </summary>
|
||||
public string ShortName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset name relative to the project root folder (without asset file extension)
|
||||
/// </summary>
|
||||
public string NamePath
|
||||
{
|
||||
get
|
||||
{
|
||||
string result = Path;
|
||||
if (result.StartsWith(Globals.ProjectFolder))
|
||||
{
|
||||
result = result.Substring(Globals.ProjectFolder.Length + 1);
|
||||
}
|
||||
return StringUtils.GetPathWithoutExtension(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default name of the content item thumbnail. Returns null if not used.
|
||||
/// </summary>
|
||||
public virtual SpriteHandle DefaultThumbnail => SpriteHandle.Invalid;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this item has default thumbnail.
|
||||
/// </summary>
|
||||
public bool HasDefaultThumbnail => DefaultThumbnail.IsValid;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item thumbnail. Warning, thumbnail may not be available if item has no references (<see cref="ReferencesCount"/>).
|
||||
/// </summary>
|
||||
public SpriteHandle Thumbnail
|
||||
{
|
||||
get => _thumbnail;
|
||||
set => _thumbnail = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if force show file extension.
|
||||
/// </summary>
|
||||
public bool ShowFileExtension;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
protected ContentItem(string path)
|
||||
: base(0, 0, DefaultWidth, DefaultHeight)
|
||||
{
|
||||
// Set path
|
||||
Path = path;
|
||||
FileName = System.IO.Path.GetFileName(path);
|
||||
ShortName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the item path. Use with caution or even don't use it. It's dangerous.
|
||||
/// </summary>
|
||||
/// <param name="value">The new path.</param>
|
||||
internal virtual void UpdatePath(string value)
|
||||
{
|
||||
Assert.AreNotEqual(Path, value);
|
||||
|
||||
// Set path
|
||||
Path = StringUtils.NormalizePath(value);
|
||||
FileName = System.IO.Path.GetFileName(value);
|
||||
ShortName = System.IO.Path.GetFileNameWithoutExtension(value);
|
||||
|
||||
// Fire event
|
||||
OnPathChanged();
|
||||
for (int i = 0; i < _references.Count; i++)
|
||||
{
|
||||
_references[i].OnItemRenamed(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the item thumbnail.
|
||||
/// </summary>
|
||||
public virtual void RefreshThumbnail()
|
||||
{
|
||||
// Skip if item has default thumbnail
|
||||
if (HasDefaultThumbnail)
|
||||
return;
|
||||
|
||||
var thumbnails = Editor.Instance.Thumbnails;
|
||||
|
||||
// Delete old thumbnail and remove it from the cache
|
||||
thumbnails.DeletePreview(this);
|
||||
|
||||
// Request new one (if need to)
|
||||
if (_references.Count > 0)
|
||||
{
|
||||
thumbnails.RequestPreview(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the tooltip text text.
|
||||
/// </summary>
|
||||
protected virtual void UpdateTooltipText()
|
||||
{
|
||||
TooltipText = "Path: " + Path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the item at the specified path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>Found item or null if missing.</returns>
|
||||
public virtual ContentItem Find(string path)
|
||||
{
|
||||
return Path == path ? this : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a specified item in the assets tree.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>True if has been found, otherwise false.</returns>
|
||||
public virtual bool Find(ContentItem item)
|
||||
{
|
||||
return this == item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the item with the specified id.
|
||||
/// </summary>
|
||||
/// <param name="id">The id.</param>
|
||||
/// <returns>Found item or null if missing.</returns>
|
||||
public virtual ContentItem Find(Guid id)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find script with the given name.
|
||||
/// </summary>
|
||||
/// <param name="scriptName">Name of the script.</param>
|
||||
/// <returns>Found script or null if missing.</returns>
|
||||
public virtual ScriptItem FindScriptWitScriptName(string scriptName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether draw item shadow.
|
||||
/// </summary>
|
||||
protected virtual bool DrawShadow => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local space rectangle for element name text area.
|
||||
/// </summary>
|
||||
public Rectangle TextRectangle
|
||||
{
|
||||
get
|
||||
{
|
||||
var view = Parent as ContentView;
|
||||
var size = Size;
|
||||
switch (view?.ViewType ?? ContentViewType.Tiles)
|
||||
{
|
||||
case ContentViewType.Tiles:
|
||||
{
|
||||
var textHeight = DefaultTextHeight * size.X / DefaultWidth;
|
||||
return new Rectangle(0, size.Y - textHeight, size.X, textHeight);
|
||||
}
|
||||
case ContentViewType.List:
|
||||
{
|
||||
var thumbnailSize = size.Y - 2 * DefaultMarginSize;
|
||||
var textHeight = Mathf.Min(size.Y, 24.0f);
|
||||
return new Rectangle(thumbnailSize + DefaultMarginSize * 2, (size.Y - textHeight) * 0.5f, size.X - textHeight - DefaultMarginSize * 3.0f, textHeight);
|
||||
}
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the item thumbnail.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The thumbnail rectangle.</param>
|
||||
public void DrawThumbnail(ref Rectangle rectangle)
|
||||
{
|
||||
// Draw shadow
|
||||
if (DrawShadow)
|
||||
{
|
||||
const float thumbnailInShadowSize = 50.0f;
|
||||
var shadowRect = rectangle.MakeExpanded((DefaultThumbnailSize - thumbnailInShadowSize) * rectangle.Width / DefaultThumbnailSize * 1.3f);
|
||||
if (!_shadowIcon.IsValid)
|
||||
_shadowIcon = Editor.Instance.Icons.AssetShadow;
|
||||
Render2D.DrawSprite(_shadowIcon, shadowRect);
|
||||
}
|
||||
|
||||
// Draw thumbnail
|
||||
if (_thumbnail.IsValid)
|
||||
Render2D.DrawSprite(_thumbnail, rectangle);
|
||||
else
|
||||
Render2D.FillRectangle(rectangle, Color.Black);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of references to that item.
|
||||
/// </summary>
|
||||
public int ReferencesCount => _references.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Adds the reference to the item.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object.</param>
|
||||
public void AddReference(IContentItemOwner obj)
|
||||
{
|
||||
Assert.IsNotNull(obj);
|
||||
Assert.IsFalse(_references.Contains(obj));
|
||||
|
||||
_references.Add(obj);
|
||||
|
||||
// Check if need to generate preview
|
||||
if (_references.Count == 1 && !_thumbnail.IsValid)
|
||||
{
|
||||
RequestThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the reference from the item.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object.</param>
|
||||
public void RemoveReference(IContentItemOwner obj)
|
||||
{
|
||||
if (_references.Remove(obj))
|
||||
{
|
||||
// Check if need to release the preview
|
||||
if (_references.Count == 0 && _thumbnail.IsValid)
|
||||
{
|
||||
ReleaseThumbnail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when item gets renamed or location gets changed (path modification).
|
||||
/// </summary>
|
||||
public virtual void OnPathChanged()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when content item gets removed (by the user or externally).
|
||||
/// </summary>
|
||||
public virtual void OnDelete()
|
||||
{
|
||||
// Fire event
|
||||
while (_references.Count > 0)
|
||||
{
|
||||
var reference = _references[0];
|
||||
reference.OnItemDeleted(this);
|
||||
RemoveReference(reference);
|
||||
}
|
||||
|
||||
// Release thumbnail
|
||||
if (_thumbnail.IsValid)
|
||||
{
|
||||
ReleaseThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when item parent folder gets changed.
|
||||
/// </summary>
|
||||
protected virtual void OnParentFolderChanged()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests the thumbnail.
|
||||
/// </summary>
|
||||
protected void RequestThumbnail()
|
||||
{
|
||||
Editor.Instance.Thumbnails.RequestPreview(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the thumbnail.
|
||||
/// </summary>
|
||||
protected void ReleaseThumbnail()
|
||||
{
|
||||
// Simply unlink sprite
|
||||
_thumbnail = SpriteHandle.Invalid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when item gets reimported or reloaded.
|
||||
/// </summary>
|
||||
protected virtual void OnReimport()
|
||||
{
|
||||
for (int i = 0; i < _references.Count; i++)
|
||||
_references[i].OnItemReimported(this);
|
||||
RefreshThumbnail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the drag and drop operation with this asset.
|
||||
/// </summary>
|
||||
protected virtual void DoDrag()
|
||||
{
|
||||
if (!CanDrag)
|
||||
return;
|
||||
|
||||
DragData data;
|
||||
|
||||
// Check if is selected
|
||||
if (Parent is ContentView view && view.IsSelected(this))
|
||||
{
|
||||
// Drag selected item
|
||||
data = DragItems.GetDragData(view.Selection);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drag single item
|
||||
data = DragItems.GetDragData(this);
|
||||
}
|
||||
|
||||
// Start drag operation
|
||||
DoDragDrop(data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool ShowTooltip => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnShowTooltip(out string text, out Vector2 location, out Rectangle area)
|
||||
{
|
||||
UpdateTooltipText();
|
||||
var result = base.OnShowTooltip(out text, out location, out area);
|
||||
location = Size * new Vector2(0.9f, 0.5f);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
// Cache data
|
||||
var size = Size;
|
||||
var style = Style.Current;
|
||||
var view = Parent as ContentView;
|
||||
var isSelected = view.IsSelected(this);
|
||||
var clientRect = new Rectangle(Vector2.Zero, size);
|
||||
var textRect = TextRectangle;
|
||||
Rectangle thumbnailRect;
|
||||
TextAlignment nameAlignment;
|
||||
switch (view.ViewType)
|
||||
{
|
||||
case ContentViewType.Tiles:
|
||||
{
|
||||
var thumbnailSize = size.X - 2 * DefaultMarginSize;
|
||||
thumbnailRect = new Rectangle(DefaultMarginSize, DefaultMarginSize, thumbnailSize, thumbnailSize);
|
||||
nameAlignment = TextAlignment.Center;
|
||||
break;
|
||||
}
|
||||
case ContentViewType.List:
|
||||
{
|
||||
var thumbnailSize = size.Y - 2 * DefaultMarginSize;
|
||||
thumbnailRect = new Rectangle(DefaultMarginSize, DefaultMarginSize, thumbnailSize, thumbnailSize);
|
||||
nameAlignment = TextAlignment.Near;
|
||||
break;
|
||||
}
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
// Draw background
|
||||
if (isSelected)
|
||||
Render2D.FillRectangle(clientRect, Parent.ContainsFocus ? style.BackgroundSelected : style.LightBackground);
|
||||
else if (IsMouseOver)
|
||||
Render2D.FillRectangle(clientRect, style.BackgroundHighlighted);
|
||||
|
||||
// Draw preview
|
||||
DrawThumbnail(ref thumbnailRect);
|
||||
|
||||
// Draw short name
|
||||
Render2D.PushClip(ref textRect);
|
||||
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 0.75f, 0.95f);
|
||||
Render2D.PopClip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
Focus();
|
||||
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
// Cache data
|
||||
_isMouseDown = true;
|
||||
_mouseDownStartPos = location;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isMouseDown)
|
||||
{
|
||||
// Clear flag
|
||||
_isMouseDown = false;
|
||||
|
||||
// Fire event
|
||||
(Parent as ContentView).OnItemClick(this);
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Vector2 location, MouseButton button)
|
||||
{
|
||||
Focus();
|
||||
|
||||
// Check if clicked on name area (and can be renamed)
|
||||
if (CanRename && TextRectangle.Contains(ref location))
|
||||
{
|
||||
// Rename
|
||||
(Parent as ContentView).OnItemDoubleClickName(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open
|
||||
(Parent as ContentView).OnItemDoubleClick(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Vector2 location)
|
||||
{
|
||||
// Check if start drag and drop
|
||||
if (_isMouseDown && Vector2.Distance(_mouseDownStartPos, location) > 10.0f)
|
||||
{
|
||||
// Clear flag
|
||||
_isMouseDown = false;
|
||||
|
||||
// Start drag drop
|
||||
DoDrag();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
// Check if start drag and drop
|
||||
if (_isMouseDown)
|
||||
{
|
||||
// Clear flag
|
||||
_isMouseDown = false;
|
||||
|
||||
// Start drag drop
|
||||
DoDrag();
|
||||
}
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
// Fire event
|
||||
while (_references.Count > 0)
|
||||
{
|
||||
var reference = _references[0];
|
||||
reference.OnItemDispose(this);
|
||||
RemoveReference(reference);
|
||||
}
|
||||
|
||||
// Release thumbnail
|
||||
if (_thumbnail.IsValid)
|
||||
{
|
||||
ReleaseThumbnail();
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Source/Editor/Content/Items/CppScriptItem.cs
Normal file
25
Source/Editor/Content/Items/CppScriptItem.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains C++ script file with source code.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ScriptItem" />
|
||||
public class CppScriptItem : ScriptItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CppScriptItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
public CppScriptItem(string path)
|
||||
: base(path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CppScript64;
|
||||
}
|
||||
}
|
||||
31
Source/Editor/Content/Items/FileItem.cs
Normal file
31
Source/Editor/Content/Items/FileItem.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item for the auxiliary files.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentItem" />
|
||||
public class FileItem : ContentItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the file.</param>
|
||||
public FileItem(string path)
|
||||
: base(path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
|
||||
}
|
||||
}
|
||||
34
Source/Editor/Content/Items/JsonAssetItem.cs
Normal file
34
Source/Editor/Content/Items/JsonAssetItem.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Asset item stored in a Json format file.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.AssetItem" />
|
||||
public class JsonAssetItem : AssetItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonAssetItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="typeName">Name of the resource type.</param>
|
||||
public JsonAssetItem(string path, Guid id, string typeName)
|
||||
: base(path, typeName, ref id)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Json;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => false;
|
||||
}
|
||||
}
|
||||
48
Source/Editor/Content/Items/NewItem.cs
Normal file
48
Source/Editor/Content/Items/NewItem.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper content item used to mock UI during creating new assets by <see cref="FlaxEditor.Windows.ContentWindow"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentItem" />
|
||||
public sealed class NewItem : ContentItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the proxy object related to the created asset.
|
||||
/// </summary>
|
||||
public ContentProxy Proxy { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the argument passed to the proxy for the item creation. In most cases it is null.
|
||||
/// </summary>
|
||||
public object Argument { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NewItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path for the new item.</param>
|
||||
/// <param name="proxy">The content proxy object.</param>
|
||||
/// <param name="arg">The argument passed to the proxy for the item creation. In most cases it is null.</param>
|
||||
public NewItem(string path, ContentProxy proxy, object arg)
|
||||
: base(path)
|
||||
{
|
||||
Proxy = proxy;
|
||||
Argument = arg;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => true;
|
||||
}
|
||||
}
|
||||
39
Source/Editor/Content/Items/PrefabItem.cs
Normal file
39
Source/Editor/Content/Items/PrefabItem.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains <see cref="FlaxEngine.Prefab"/> data.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.JsonAssetItem" />
|
||||
public sealed class PrefabItem : JsonAssetItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrefabItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The asset path.</param>
|
||||
/// <param name="id">The asset identifier.</param>
|
||||
public PrefabItem(string path, Guid id)
|
||||
: base(path, id, PrefabProxy.AssetTypename)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Asset;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Prefab;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => SpriteHandle.Invalid;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsOfType(Type type)
|
||||
{
|
||||
return type.IsAssignableFrom(typeof(Prefab));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Source/Editor/Content/Items/SceneItem.cs
Normal file
39
Source/Editor/Content/Items/SceneItem.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains <see cref="FlaxEngine.Scene"/> data.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.JsonAssetItem" />
|
||||
public sealed class SceneItem : JsonAssetItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SceneItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The asset path.</param>
|
||||
/// <param name="id">The asset identifier.</param>
|
||||
public SceneItem(string path, Guid id)
|
||||
: base(path, id, Scene.EditorPickerTypename)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Scene;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Scene;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene64;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsOfType(Type type)
|
||||
{
|
||||
return type.IsAssignableFrom(typeof(SceneAsset));
|
||||
}
|
||||
}
|
||||
}
|
||||
97
Source/Editor/Content/Items/ScriptItem.cs
Normal file
97
Source/Editor/Content/Items/ScriptItem.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains script file with source code.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentItem" />
|
||||
public abstract class ScriptItem : ContentItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the script (deducted from the asset name).
|
||||
/// </summary>
|
||||
public string ScriptName => FilterScriptName(ShortName);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the script item references the valid use script type that can be used in a gameplay.
|
||||
/// </summary>
|
||||
public bool IsValid => ScriptsBuilder.FindScript(ScriptName) != null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScriptItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
protected ScriptItem(string path)
|
||||
: base(path)
|
||||
{
|
||||
ShowFileExtension = true;
|
||||
}
|
||||
|
||||
private static string FilterScriptName(string input)
|
||||
{
|
||||
var length = input.Length;
|
||||
var sb = new StringBuilder(length);
|
||||
|
||||
// Skip leading '0-9' characters
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var c = input[i];
|
||||
|
||||
if (char.IsLetterOrDigit(c) && !char.IsDigit(c))
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove all characters that are not '_' or 'a-z' or 'A-Z' or '0-9'
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var c = input[i];
|
||||
|
||||
if (c == '_' || char.IsLetterOrDigit(c))
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the name of the script for the given file.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>Script name</returns>
|
||||
public static string CreateScriptName(string path)
|
||||
{
|
||||
return FilterScriptName(System.IO.Path.GetFileNameWithoutExtension(path));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Script;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Script;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ScriptItem FindScriptWitScriptName(string scriptName)
|
||||
{
|
||||
return scriptName == ScriptName ? this : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPathChanged()
|
||||
{
|
||||
ScriptsBuilder.MarkWorkspaceDirty();
|
||||
|
||||
base.OnPathChanged();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDelete()
|
||||
{
|
||||
ScriptsBuilder.MarkWorkspaceDirty();
|
||||
|
||||
base.OnDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Source/Editor/Content/Items/ShaderSourceItem.cs
Normal file
32
Source/Editor/Content/Items/ShaderSourceItem.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Content item that contains shader source code.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentItem" />
|
||||
public class ShaderSourceItem : ContentItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderSourceItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the item.</param>
|
||||
public ShaderSourceItem(string path)
|
||||
: base(path)
|
||||
{
|
||||
ShowFileExtension = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Asset;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Shader;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
|
||||
}
|
||||
}
|
||||
552
Source/Editor/Content/Items/VisualScriptItem.cs
Normal file
552
Source/Editor/Content/Items/VisualScriptItem.cs
Normal file
@@ -0,0 +1,552 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Json;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
sealed class VisualScriptParameterInfo : IScriptMemberInfo
|
||||
{
|
||||
private readonly VisualScriptType _type;
|
||||
private readonly VisjectGraphParameter _parameter;
|
||||
|
||||
internal VisualScriptParameterInfo(VisualScriptType type, VisjectGraphParameter parameter)
|
||||
{
|
||||
_type = type;
|
||||
_parameter = parameter;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => _parameter.Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => _parameter.IsPublic;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsStatic => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsVirtual => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAbstract => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGeneric => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsField => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsProperty => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsMethod => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasGet => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasSet => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int ParametersCount => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptType DeclaringType => new ScriptType(_type);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptType ValueType
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = TypeUtils.GetType(_parameter.TypeTypeName);
|
||||
return type ? type : new ScriptType(_parameter.Type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
return Surface.SurfaceMeta.HasAttribute(_parameter, attributeType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object[] GetAttributes(bool inherit)
|
||||
{
|
||||
return Surface.SurfaceMeta.GetAttributes(_parameter);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo.Parameter[] GetParameters()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object GetValue(object obj)
|
||||
{
|
||||
return _type.Asset.GetScriptInstanceParameterValue(_parameter.Name, (Object)obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetValue(object obj, object value)
|
||||
{
|
||||
_type.Asset.SetScriptInstanceParameterValue(_parameter.Name, (Object)obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class VisualScriptMethodInfo : IScriptMemberInfo
|
||||
{
|
||||
[Flags]
|
||||
private enum Flags
|
||||
{
|
||||
None = 0,
|
||||
Static = 1,
|
||||
Virtual = 2,
|
||||
Override = 4,
|
||||
}
|
||||
|
||||
private readonly VisualScriptType _type;
|
||||
private readonly int _index;
|
||||
private readonly string _name;
|
||||
private readonly byte _flags;
|
||||
private readonly ScriptType _returnType;
|
||||
private readonly ScriptMemberInfo.Parameter[] _parameters;
|
||||
private object[] _attributes;
|
||||
|
||||
internal VisualScriptMethodInfo(VisualScriptType type, int index)
|
||||
{
|
||||
_type = type;
|
||||
_index = index;
|
||||
type.Asset.GetMethodSignature(index, out _name, out _flags, out var returnTypeName, out var paramNames, out var paramTypeNames, out var paramOuts);
|
||||
_returnType = TypeUtils.GetType(returnTypeName);
|
||||
if (paramNames.Length != 0)
|
||||
{
|
||||
_parameters = new ScriptMemberInfo.Parameter[paramNames.Length];
|
||||
for (int i = 0; i < _parameters.Length; i++)
|
||||
{
|
||||
_parameters[i] = new ScriptMemberInfo.Parameter
|
||||
{
|
||||
Name = paramNames[i],
|
||||
Type = TypeUtils.GetType(paramTypeNames[i]),
|
||||
IsOut = paramOuts[i],
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_parameters = Utils.GetEmptyArray<ScriptMemberInfo.Parameter>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => _name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsStatic => (_flags & (byte)Flags.Static) != 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsVirtual => (_flags & (byte)Flags.Virtual) != 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAbstract => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGeneric => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsField => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsProperty => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsMethod => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasGet => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasSet => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int ParametersCount => _parameters.Length;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptType DeclaringType => (_flags & (byte)Flags.Override) != 0 ? _type.BaseType : new ScriptType(_type);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptType ValueType => _returnType;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
return GetAttributes(inherit).Any(x => x.GetType() == attributeType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object[] GetAttributes(bool inherit)
|
||||
{
|
||||
if (_attributes == null)
|
||||
{
|
||||
var data = _type.Asset.GetMethodMetaData(_index, Surface.SurfaceMeta.AttributeMetaTypeID);
|
||||
_attributes = Surface.SurfaceMeta.GetAttributes(data);
|
||||
}
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo.Parameter[] GetParameters()
|
||||
{
|
||||
return _parameters;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object GetValue(object obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetValue(object obj, object value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The implementation of the <see cref="IScriptType"/>
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Scripting.IScriptType" />
|
||||
[HideInEditor]
|
||||
public sealed class VisualScriptType : IScriptType
|
||||
{
|
||||
private VisualScript _asset;
|
||||
private ScriptMemberInfo[] _parameters;
|
||||
private ScriptMemberInfo[] _methods;
|
||||
private object[] _attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Visual Script asset that contains this type.
|
||||
/// </summary>
|
||||
public VisualScript Asset => _asset;
|
||||
|
||||
internal VisualScriptType(VisualScript asset)
|
||||
{
|
||||
_asset = asset;
|
||||
}
|
||||
|
||||
private void CacheData()
|
||||
{
|
||||
if (_parameters != null)
|
||||
return;
|
||||
if (_asset.WaitForLoaded())
|
||||
return;
|
||||
FlaxEngine.Content.AssetReloading += OnAssetReloading;
|
||||
|
||||
// Cache Visual Script parameters info
|
||||
var parameters = _asset.Parameters;
|
||||
if (parameters.Length != 0)
|
||||
{
|
||||
_parameters = new ScriptMemberInfo[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
_parameters[i] = new ScriptMemberInfo(new VisualScriptParameterInfo(this, parameters[i]));
|
||||
}
|
||||
else
|
||||
_parameters = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
|
||||
// Cache Visual Script methods info
|
||||
var methodsCount = _asset.GetMethodsCount();
|
||||
if (methodsCount != 0)
|
||||
{
|
||||
_methods = new ScriptMemberInfo[methodsCount];
|
||||
for (int i = 0; i < methodsCount; i++)
|
||||
_methods[i] = new ScriptMemberInfo(new VisualScriptMethodInfo(this, i));
|
||||
}
|
||||
else
|
||||
_methods = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
|
||||
// Cache Visual Script attributes
|
||||
var attributesData = _asset.GetMetaData(Surface.SurfaceMeta.AttributeMetaTypeID);
|
||||
if (attributesData != null && attributesData.Length != 0)
|
||||
{
|
||||
_attributes = Surface.SurfaceMeta.GetAttributes(attributesData);
|
||||
}
|
||||
else
|
||||
_attributes = Utils.GetEmptyArray<object>();
|
||||
}
|
||||
|
||||
private void OnAssetReloading(Asset asset)
|
||||
{
|
||||
if (asset == _asset)
|
||||
{
|
||||
_parameters = null;
|
||||
_methods = null;
|
||||
FlaxEngine.Content.AssetReloading -= OnAssetReloading;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
_asset = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Path.GetFileNameWithoutExtension(_asset.Path);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Namespace => string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string TypeName => JsonSerializer.GetStringID(_asset.ID);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAbstract => _asset && !_asset.WaitForLoaded() && (_asset.Meta.Flags & VisualScript.Flags.Abstract) != 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsSealed => _asset && !_asset.WaitForLoaded() && (_asset.Meta.Flags & VisualScript.Flags.Sealed) != 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnum => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsClass => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsArray => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsValueType => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGenericType => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReference => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPointer => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsStatic => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanCreateInstance => !IsAbstract;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptType BaseType => _asset && !_asset.WaitForLoaded() ? TypeUtils.GetType(_asset.Meta.BaseTypename) : ScriptType.Null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ContentItem ContentItem => _asset ? Editor.Instance.ContentDatabase.FindAsset(_asset.ID) : null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object CreateInstance()
|
||||
{
|
||||
return Object.New(TypeName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
if (inherit && BaseType.HasAttribute(attributeType, true))
|
||||
return true;
|
||||
CacheData();
|
||||
return _attributes.Any(x => x.GetType() == attributeType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object[] GetAttributes(bool inherit)
|
||||
{
|
||||
CacheData();
|
||||
if (inherit)
|
||||
{
|
||||
var thisAttributes = _attributes;
|
||||
var baseAttributes = BaseType.GetAttributes(true);
|
||||
if (thisAttributes.Length != 0)
|
||||
{
|
||||
if (baseAttributes.Length != 0)
|
||||
{
|
||||
var resultAttributes = new object[thisAttributes.Length + baseAttributes.Length];
|
||||
Array.Copy(thisAttributes, 0, resultAttributes, 0, thisAttributes.Length);
|
||||
Array.Copy(baseAttributes, 0, resultAttributes, thisAttributes.Length, baseAttributes.Length);
|
||||
return resultAttributes;
|
||||
}
|
||||
return thisAttributes;
|
||||
}
|
||||
return baseAttributes;
|
||||
}
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo[] GetMembers(string name, MemberTypes type, BindingFlags bindingAttr)
|
||||
{
|
||||
var members = new List<ScriptMemberInfo>();
|
||||
if ((bindingAttr & BindingFlags.DeclaredOnly) == 0)
|
||||
{
|
||||
var baseType = BaseType;
|
||||
if (baseType)
|
||||
members.AddRange(baseType.GetMembers(name, type, bindingAttr));
|
||||
}
|
||||
CacheData();
|
||||
if ((type & MemberTypes.Field) != 0)
|
||||
{
|
||||
foreach (var parameter in _parameters)
|
||||
{
|
||||
if (parameter.Filter(name, bindingAttr))
|
||||
members.Add(parameter);
|
||||
}
|
||||
}
|
||||
if ((type & MemberTypes.Method) != 0)
|
||||
{
|
||||
foreach (var method in _methods)
|
||||
{
|
||||
if (method.Filter(name, bindingAttr))
|
||||
members.Add(method);
|
||||
}
|
||||
}
|
||||
return members.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo[] GetMembers(BindingFlags bindingAttr)
|
||||
{
|
||||
var members = new List<ScriptMemberInfo>();
|
||||
if ((bindingAttr & BindingFlags.DeclaredOnly) == 0)
|
||||
{
|
||||
var baseType = BaseType;
|
||||
if (baseType)
|
||||
members.AddRange(baseType.GetMembers(bindingAttr));
|
||||
}
|
||||
CacheData();
|
||||
foreach (var parameter in _parameters)
|
||||
{
|
||||
if (parameter.Filter(bindingAttr))
|
||||
members.Add(parameter);
|
||||
}
|
||||
foreach (var method in _methods)
|
||||
{
|
||||
if (method.Filter(bindingAttr))
|
||||
members.Add(method);
|
||||
}
|
||||
return members.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo[] GetFields(BindingFlags bindingAttr)
|
||||
{
|
||||
CacheData();
|
||||
var baseType = BaseType;
|
||||
if (baseType)
|
||||
{
|
||||
var baseFields = baseType.GetFields(bindingAttr);
|
||||
var newArray = new ScriptMemberInfo[_parameters.Length + baseFields.Length];
|
||||
Array.Copy(_parameters, newArray, _parameters.Length);
|
||||
Array.Copy(baseFields, 0, newArray, _parameters.Length, baseFields.Length);
|
||||
return newArray;
|
||||
}
|
||||
return _parameters;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo[] GetProperties(BindingFlags bindingAttr)
|
||||
{
|
||||
var baseType = BaseType;
|
||||
if (baseType)
|
||||
return baseType.GetProperties(bindingAttr);
|
||||
return Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptMemberInfo[] GetMethods(BindingFlags bindingAttr)
|
||||
{
|
||||
CacheData();
|
||||
var baseType = BaseType;
|
||||
if (baseType)
|
||||
{
|
||||
var baseMethods = baseType.GetMethods(bindingAttr);
|
||||
var newArray = new ScriptMemberInfo[_methods.Length + baseMethods.Length];
|
||||
Array.Copy(_methods, newArray, _methods.Length);
|
||||
Array.Copy(baseMethods, 0, newArray, _methods.Length, baseMethods.Length);
|
||||
return newArray;
|
||||
}
|
||||
return _methods;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="VisualScript"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class VisualScriptItem : BinaryAssetItem
|
||||
{
|
||||
/// <summary>
|
||||
/// The cached list of all Visual Script assets found in the workspace (engine, game and plugin projects). Updated on workspace modifications.
|
||||
/// </summary>
|
||||
public static readonly List<VisualScriptItem> VisualScripts = new List<VisualScriptItem>();
|
||||
|
||||
private VisualScriptType _scriptType;
|
||||
|
||||
/// <summary>
|
||||
/// The Visual Script type. Can be null if failed to load asset.
|
||||
/// </summary>
|
||||
public ScriptType ScriptType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_scriptType == null)
|
||||
{
|
||||
var asset = FlaxEngine.Content.LoadAsync<VisualScript>(ID);
|
||||
if (asset)
|
||||
_scriptType = new VisualScriptType(asset);
|
||||
}
|
||||
return new ScriptType(_scriptType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public VisualScriptItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Script)
|
||||
{
|
||||
VisualScripts.Add(this);
|
||||
Editor.Instance.CodeEditing.ClearTypes();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CodeScript64;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
if (_scriptType != null)
|
||||
{
|
||||
Editor.Instance.CodeEditing.ClearTypes();
|
||||
_scriptType.Dispose();
|
||||
_scriptType = null;
|
||||
}
|
||||
VisualScripts.Remove(this);
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user