245 lines
7.0 KiB
C#
245 lines
7.0 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.Text.RegularExpressions;
|
||
using JetBrains.Annotations;
|
||
using Needle.Engine.Utils;
|
||
using Newtonsoft.Json;
|
||
using UnityEditor;
|
||
using UnityEditor.Callbacks;
|
||
using UnityEngine;
|
||
using UnityEngine.UIElements;
|
||
|
||
namespace Needle.Engine.Samples
|
||
{
|
||
[CreateAssetMenu(menuName = "Needle Engine/Samples/Sample Info")]
|
||
internal class SampleInfo : ScriptableObject
|
||
{
|
||
[UsedImplicitly]
|
||
public string Name
|
||
{
|
||
get => DisplayNameOrName;
|
||
set => DisplayName = value;
|
||
}
|
||
|
||
[Serializable]
|
||
public class ComponentList
|
||
{
|
||
public string Component;
|
||
public string Path;
|
||
public string MoreInfoUrl;
|
||
}
|
||
|
||
[JsonIgnore]
|
||
public string DisplayName;
|
||
public string Description;
|
||
public Texture2D Thumbnail;
|
||
[JsonIgnore]
|
||
public SceneAsset Scene;
|
||
public string LiveUrl;
|
||
public int Priority;
|
||
[JsonIgnore]
|
||
public string DisplayNameOrName => !string.IsNullOrWhiteSpace(DisplayName) ? DisplayName : ObjectNames.NicifyVariableName(name);
|
||
public Tag[] Tags;
|
||
|
||
[JsonIgnore][HideInInspector]
|
||
public SampleInfo reference;
|
||
|
||
public ComponentList[] UsedComponents;
|
||
|
||
/// <summary>
|
||
/// Git directory relative path to the scene
|
||
/// </summary>
|
||
[JsonProperty("ReadmeUrl")]
|
||
private string ReadmeUrl
|
||
{
|
||
get
|
||
{
|
||
if (!Scene) return "";
|
||
var sceneAssetPath = AssetDatabase.GetAssetPath(Scene);
|
||
if (sceneAssetPath == null)
|
||
{
|
||
Debug.LogError("Missing scene asset path...", this);
|
||
return "";
|
||
}
|
||
return Constants.RepoRoot + MakeGitDirectoryRelative(sceneAssetPath) + "/README.md";
|
||
}
|
||
}
|
||
|
||
private string MakeGitDirectoryRelative(string str)
|
||
{
|
||
var abs = Path.GetDirectoryName(Path.GetFullPath(str))?.Replace("\\", "/");
|
||
var dirInfo = new FileInfo(str).Directory;
|
||
var gitDirectory = dirInfo;
|
||
while (gitDirectory != null && gitDirectory.Exists)
|
||
{
|
||
var fileOrDir = gitDirectory.GetFileSystemInfos(".git");
|
||
if (fileOrDir.Length > 0)
|
||
{
|
||
break;
|
||
}
|
||
gitDirectory = gitDirectory.Parent;
|
||
}
|
||
var gitPath = gitDirectory?.FullName.Replace("\\", "/");
|
||
var gitRelative = abs.Substring(gitPath!.Length);
|
||
while (gitRelative.StartsWith("/"))
|
||
gitRelative = gitRelative.Substring(1);
|
||
return gitRelative;
|
||
}
|
||
|
||
private void OnValidate()
|
||
{
|
||
if (!Scene)
|
||
{
|
||
var path = AssetDatabase.GetAssetPath(this);
|
||
if (string.IsNullOrWhiteSpace(path)) return;
|
||
var scenes = AssetDatabase.FindAssets("t:SceneAsset", new[] { Path.GetDirectoryName(path) });
|
||
foreach (var guid in scenes)
|
||
{
|
||
var scene = AssetDatabase.LoadAssetAtPath<SceneAsset>(AssetDatabase.GUIDToAssetPath(guid));
|
||
Scene = scene;
|
||
if (scene)
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
|
||
[OnOpenAsset(100)]
|
||
private static bool OpenAsset(int instanceID, int line)
|
||
{
|
||
// Handle SampleInfo assets
|
||
if (EditorUtility.InstanceIDToObject(instanceID) is SampleInfo sampleInfo)
|
||
{
|
||
SamplesWindow.OpenScene(sampleInfo.Scene);
|
||
return true;
|
||
}
|
||
|
||
// Handle scenes that are part of a sample / immutable
|
||
if (EditorUtility.InstanceIDToObject(instanceID) is SceneAsset sceneAsset)
|
||
{
|
||
var scenePath = AssetDatabase.GetAssetPath(sceneAsset);
|
||
if (PackageUtils.IsMutable(scenePath))
|
||
return false;
|
||
SamplesWindow.OpenScene(sceneAsset);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
#endif
|
||
|
||
public override string ToString()
|
||
{
|
||
return DisplayNameOrName + " – " + name;
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
[ContextMenu("Open local Readme")]
|
||
void OpenReadme()
|
||
{
|
||
var readmeFile = Path.GetDirectoryName(AssetDatabase.GetAssetPath(Scene)) + "/README.md";
|
||
if (!File.Exists(readmeFile)) return;
|
||
AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<TextAsset>(readmeFile));
|
||
}
|
||
#endif
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
|
||
[CustomEditor(typeof(SampleInfo), true)]
|
||
[CanEditMultipleObjects]
|
||
class SampleInfoEditor : Editor
|
||
{
|
||
public override VisualElement CreateInspectorGUI()
|
||
{
|
||
// if we have multiple sample assets selected just use the default inspector (for editing multiple tags at once)
|
||
if (targets.Length > 1) return null;
|
||
var t = target as SampleInfo;
|
||
if (!t) return new Label("<null>");
|
||
|
||
var isSubAsset = AssetDatabase.IsSubAsset(t);
|
||
var v = new VisualElement();
|
||
foreach (var style in SamplesWindow.StyleSheet)
|
||
v.styleSheets.Add(style);
|
||
|
||
if (!EditorGUIUtility.isProSkin) v.AddToClassList("__light");
|
||
var sample = new SamplesWindow.Sample(t);
|
||
sample.style.marginLeft = -10;
|
||
sample.style.marginRight = -10;
|
||
v.Add(sample);
|
||
|
||
var readmeFile = Path.GetDirectoryName(AssetDatabase.GetAssetPath(t.Scene)) + "/README.md";
|
||
var readmeText = File.ReadAllText(readmeFile);
|
||
var readmeRichText = ConvertMarkdownToRichText(readmeText);
|
||
|
||
GUIStyle _readmeStyle = null;
|
||
|
||
var label = new IMGUIContainer(() =>
|
||
{
|
||
if (_readmeStyle == null)
|
||
{
|
||
_readmeStyle= new GUIStyle(GUI.skin.label);
|
||
_readmeStyle.wordWrap = true;
|
||
_readmeStyle.richText = true;
|
||
_readmeStyle.fixedHeight = 0;
|
||
_readmeStyle.stretchHeight = true;
|
||
|
||
}
|
||
// Links are not clickable here for some reason...
|
||
// with SelectableLabel they are, but then the layout is messed up.
|
||
var content = new GUIContent(readmeRichText);
|
||
GUILayout.Label(content.text, _readmeStyle);
|
||
});
|
||
|
||
if (!isSubAsset)
|
||
{
|
||
var container = new IMGUIContainer(() => DrawDefaultInspector());
|
||
container.style.marginTop = 20;
|
||
v.Add(container);
|
||
|
||
// Show the readme text
|
||
v.Add(label);
|
||
}
|
||
else
|
||
v.style.maxHeight = 500;
|
||
|
||
return v;
|
||
}
|
||
|
||
// Copied from Readme.cs (different packages)
|
||
public static string ConvertMarkdownToRichText(string markdown)
|
||
{
|
||
// Convert headers
|
||
markdown = Regex.Replace(markdown, @"^#\s+(.+)$", "<b><size=24>$1</size></b>", RegexOptions.Multiline);
|
||
markdown = Regex.Replace(markdown, @"^##\s+(.+)$", "<b><size=16>$1</size></b>", RegexOptions.Multiline);
|
||
markdown = Regex.Replace(markdown, @"^###\s+(.+)$", "<b><size=12>$1</size></b>", RegexOptions.Multiline);
|
||
|
||
// Convert bold
|
||
markdown = Regex.Replace(markdown, @"\*\*(.+?)\*\*", "<b>$1</b>");
|
||
markdown = Regex.Replace(markdown, @"__(.+?)__", "<b>$1</b>");
|
||
|
||
// Convert italic
|
||
markdown = Regex.Replace(markdown, @"\*(.+?)\*", "<i>$1</i>");
|
||
//markdown = Regex.Replace(markdown, @"_(.+?)_", "<i>$1</i>"); // fails?
|
||
|
||
// Convert block
|
||
markdown = Regex.Replace(markdown, @"```([^`]+)```", "<color=#7894bf><i>\n-----$1-----\n</i></color>");
|
||
|
||
// Convert inline-block
|
||
markdown = Regex.Replace(markdown, @"\`(.+?)\`", "<color=#aaa><i>$1</i></color>");
|
||
|
||
// Convert lists (assuming unordered lists)
|
||
markdown = Regex.Replace(markdown, @"^\s*-\s+(.+)$", "• $1", RegexOptions.Multiline);
|
||
|
||
// Convert links
|
||
markdown = Regex.Replace(markdown, @"\[([^\]]+)\]\(([^\)]+)\)","<a href=\"$2\">$1</a>");
|
||
|
||
// Replace sequence of at least three --- with a horizontal line
|
||
markdown = Regex.Replace(markdown, @"-{3,}", "<color=#fff4>––––––––––</color>");
|
||
|
||
return markdown;
|
||
}
|
||
}
|
||
#endif
|
||
} |