diff --git a/Core/AssetPathAttribute.cs b/Core/AssetPathAttribute.cs new file mode 100644 index 00000000..88cf15e9 --- /dev/null +++ b/Core/AssetPathAttribute.cs @@ -0,0 +1,17 @@ +using System; +using JetBrains.Annotations; + +namespace UIComponents.Core +{ + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)] + [BaseTypeRequired(typeof(UIComponent))] + public class AssetPathAttribute : Attribute + { + public readonly string Path; + + public AssetPathAttribute(string path) + { + Path = path; + } + } +} \ No newline at end of file diff --git a/Core/AssetPathAttribute.cs.meta b/Core/AssetPathAttribute.cs.meta new file mode 100644 index 00000000..f8f0d9fe --- /dev/null +++ b/Core/AssetPathAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a6f9ab71d40f453294d64d17eb37c692 +timeCreated: 1651143459 \ No newline at end of file diff --git a/Core/PathAttribute.cs b/Core/PathAttribute.cs index ad4b7c19..9947b02e 100644 --- a/Core/PathAttribute.cs +++ b/Core/PathAttribute.cs @@ -1,22 +1,75 @@ using System; +using UnityEditor; namespace UIComponents.Core { public abstract class PathAttribute : Attribute { public string Path { get; protected set; } - - public string RelativeTo { get; set; } - public string GetAssetPath() + public string GetAssetPathForComponent(UIComponent component) { if (Path == null) Path = string.Empty; - if (!string.IsNullOrEmpty(RelativeTo)) - return string.Join("/", RelativeTo, Path); + if (!ConfiguredPathIsComplete()) + { + if (TryGetPathFromComponent(component, out var pathFromComponent)) + Path = pathFromComponent; + else if (TryGetPathFromAssembly(component, out var pathFromAssembly)) + Path = pathFromAssembly; + } return Path; } + + private bool ConfiguredPathIsComplete() + { + return Path.StartsWith("Assets/") || + Path.StartsWith("Packages/"); + } + + private bool TryGetPathFromComponent(UIComponent component, out string path) + { + path = ""; + + return TryGetValidAssetPathFromAttributes(component.AssetPathAttributes, out path); + } + + private bool TryGetPathFromAssembly(UIComponent component, out string path) + { + path = ""; + + var assembly = component.GetType().Assembly; + + var assetPathAttributes = + assembly.GetCustomAttributes(typeof(AssetPathAttribute), false); + + return TryGetValidAssetPathFromAttributes((AssetPathAttribute[]) assetPathAttributes, out path); + } + + private bool TryGetValidAssetPathFromAttributes( + AssetPathAttribute[] attributes, + out string path) + { + path = ""; + + if (attributes.Length == 0) + return false; + + foreach (var attribute in attributes) + { + var filePath = string.Join("/", attribute.Path, Path); + + if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(filePath))) + continue; + + path = filePath; + + return true; + } + + return false; + } } } \ No newline at end of file diff --git a/Core/UIComponent.cs b/Core/UIComponent.cs index 13287889..7095e394 100644 --- a/Core/UIComponent.cs +++ b/Core/UIComponent.cs @@ -15,6 +15,8 @@ public abstract class UIComponent : VisualElement private readonly StylesheetAttribute[] _stylesheetAttributes; + internal readonly AssetPathAttribute[] AssetPathAttributes; + private static readonly Dictionary InjectorDictionary = new Dictionary(); @@ -31,7 +33,8 @@ public abstract class UIComponent : VisualElement protected UIComponent() { _componentType = GetType(); - _layoutAttribute = GetLayoutAttribute(); + _layoutAttribute = GetSingleAttribute(); + AssetPathAttributes = GetAttributes(); _stylesheetAttributes = GetAttributes(); var type = GetType(); @@ -55,8 +58,10 @@ protected virtual VisualTreeAsset GetLayout() { if (_layoutAttribute == null) return null; + + var assetPath = _layoutAttribute.GetAssetPathForComponent(this); - return AssetDatabase.LoadAssetAtPath(_layoutAttribute.GetAssetPath()); + return AssetDatabase.LoadAssetAtPath(assetPath); } protected virtual StyleSheet[] GetStyleSheets() @@ -65,17 +70,25 @@ protected virtual StyleSheet[] GetStyleSheets() for (var i = 0; i < _stylesheetAttributes.Length; i++) { - var assetPath = _stylesheetAttributes[i].GetAssetPath(); - loadedStyleSheets[i] = AssetDatabase.LoadAssetAtPath(assetPath); + var assetPath = _stylesheetAttributes[i].GetAssetPathForComponent(this); + var styleSheet = AssetDatabase.LoadAssetAtPath(assetPath); + + if (styleSheet == null) + { + Debug.LogError($"Could not find stylesheet {assetPath} for {GetType().Name}"); + continue; + } + + loadedStyleSheets[i] = styleSheet; } return loadedStyleSheets; } - + [CanBeNull] - private LayoutAttribute GetLayoutAttribute() + private T GetSingleAttribute() where T : Attribute { - var layoutAttributes = GetAttributes(); + var layoutAttributes = GetAttributes(); if (layoutAttributes.Length == 0) return null;