Skip to content

Commit 3c218a0

Browse files
committed
General Improvements
Log story short, I haven't worked on this package since may and forgot to update it. I have updated tests and improved parsing to actions as well. Right now I am reworking the codebase to support transitions.
1 parent 7856c13 commit 3c218a0

File tree

85 files changed

+1448
-661
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1448
-661
lines changed

Editor/MotionCollection.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
2-
<engine:VisualElement name="effect-element" style="flex-grow: 1; margin-bottom: 5px;">
3-
<editor:Toolbar style="border-top-width: 1px; border-bottom-width: 0; background-color: rgba(255, 255, 255, 0.05); align-items: center; justify-content: space-between;">
2+
<engine:VisualElement name="element" style="margin-bottom: 0;">
3+
<editor:Toolbar name="header" style="border-top-width: 1px; border-bottom-width: 0; background-color: rgba(255, 255, 255, 0.05); align-items: center; justify-content: space-between; margin-top: 0; -unity-font-style: bold;">
44
<engine:Label text="Wave Effect" name="label" style="justify-content: flex-start; align-self: auto; -unity-text-align: middle-left;" />
55
<editor:ToolbarButton text="⋮" name="options-button" style="font-size: 23px; border-right-width: 0; border-left-width: 0; background-color: rgba(60, 60, 60, 0);" />
66
</editor:Toolbar>
7-
<editor:ToolbarSpacer style="flex-grow: 1;" />
8-
<engine:GroupBox name="content" style="margin-top: 0;" />
7+
<engine:GroupBox name="body" style="margin-top: 0; display: none;" />
98
</engine:VisualElement>
109
</engine:UXML>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
2+
<engine:VisualElement style="flex-grow: 1;">
3+
<engine:VisualElement name="elements-list" />
4+
<engine:Button text="Add" name="add-element-button" />
5+
</engine:VisualElement>
6+
</engine:UXML>

Editor/MotionCollection/ListContainer.uxml.meta

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using BP.TextMotion;
2+
using System.Linq;
3+
using System.Reflection;
4+
using UnityEditor;
5+
using UnityEditor.UIElements;
6+
using UnityEngine;
7+
using UnityEngine.UIElements;
8+
9+
namespace BP.TextMotionEditor
10+
{
11+
12+
[CustomPropertyDrawer(typeof(MotionCollection<>), true)]
13+
public class MotionCollectionEditor : PropertyDrawer
14+
{
15+
[SerializeField] private VisualTreeAsset listContainerAsset;
16+
[SerializeField] private VisualTreeAsset elementContainerAsset;
17+
18+
public override VisualElement CreatePropertyGUI(SerializedProperty property)
19+
{
20+
var root = listContainerAsset.CloneTree();
21+
var listRoot = root.Q<VisualElement>("elements-list");
22+
var addButton = root.Q<Button>("add-element-button");
23+
var listProp = property.FindPropertyRelative("components");
24+
25+
void RefreshList()
26+
{
27+
listRoot.Clear();
28+
for (int i = 0; i < listProp.arraySize; i++)
29+
{
30+
var elementProp = listProp.GetArrayElementAtIndex(i);
31+
var objRef = elementProp.objectReferenceValue as MotionComponent;
32+
if (objRef == null) continue;
33+
34+
var elemContainer = elementContainerAsset.CloneTree();
35+
var header = elemContainer.Q<VisualElement>("header");
36+
var body = elemContainer.Q<VisualElement>("body");
37+
var optionsButton = elemContainer.Q<ToolbarButton>("options-button");
38+
39+
var type = objRef.GetType();
40+
var attr = type.GetCustomAttribute<TextMotionAttribute>();
41+
var displayName = attr != null ? attr.DisplayName : type.Name;
42+
header.Q<Label>("label").text = displayName;
43+
44+
var so = new SerializedObject(objRef);
45+
body.Add(DrawEditor(so));
46+
47+
var isFoldedProp = so.FindProperty("isFolded");
48+
void UpdateBody()
49+
{
50+
body.style.display = isFoldedProp.boolValue ? DisplayStyle.Flex : DisplayStyle.None;
51+
}
52+
UpdateBody();
53+
header.TrackPropertyValue(isFoldedProp, (prop) => UpdateBody());
54+
header.RegisterCallback<ClickEvent>(evt =>
55+
{
56+
isFoldedProp.boolValue = !isFoldedProp.boolValue;
57+
so.ApplyModifiedProperties();
58+
});
59+
60+
61+
// Remove button
62+
optionsButton.clicked += () =>
63+
{
64+
var menu = new GenericDropdownMenu();
65+
menu.AddItem("Remove", false, () =>
66+
{
67+
var listTarget = property.serializedObject.targetObject as ScriptableObject;
68+
Undo.RecordObject(listTarget, "Remove Component");
69+
listProp.DeleteArrayElementAtIndex(i);
70+
property.serializedObject.ApplyModifiedProperties();
71+
RefreshList();
72+
});
73+
menu.DropDown(optionsButton.worldBound, optionsButton, false);
74+
};
75+
76+
listRoot.Add(elemContainer);
77+
}
78+
}
79+
80+
addButton.clicked += () =>
81+
{
82+
var menu = new GenericMenu();
83+
var registry = MotionEffectRegistry.Components;
84+
foreach (var entry in registry)
85+
{
86+
if (Enumerable
87+
.Range(0, listProp.arraySize)
88+
.Select(i => listProp.GetArrayElementAtIndex(i).objectReferenceValue)
89+
.Any(obj => obj != null && obj.GetType() == entry.Type))
90+
{
91+
continue;
92+
}
93+
94+
menu.AddItem(new GUIContent(entry.DisplayName), false, () =>
95+
{
96+
var listTarget = property.serializedObject.targetObject as ScriptableObject;
97+
Undo.RecordObject(listTarget, "Add Component");
98+
99+
var inst = ScriptableObject.CreateInstance(entry.Type);
100+
inst.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
101+
102+
AssetDatabase.AddObjectToAsset(inst,
103+
AssetDatabase.GetAssetPath(listTarget));
104+
105+
listProp.arraySize++;
106+
var newElem = listProp.GetArrayElementAtIndex(listProp.arraySize - 1);
107+
newElem.objectReferenceValue = inst;
108+
property.serializedObject.ApplyModifiedProperties();
109+
110+
RefreshList();
111+
});
112+
}
113+
menu.ShowAsContext();
114+
};
115+
116+
RefreshList();
117+
return root;
118+
}
119+
120+
private VisualElement DrawEditor(SerializedObject serializedObject)
121+
{
122+
var targetObject = serializedObject.targetObject;
123+
var editor = Editor.CreateEditor(targetObject);
124+
if (!editor)
125+
{
126+
return new Label("No editor implemented");
127+
}
128+
129+
var visualElement = editor.CreateInspectorGUI();
130+
if (visualElement != null)
131+
{
132+
return visualElement;
133+
}
134+
135+
var container = new IMGUIContainer(() =>
136+
{
137+
serializedObject.Update();
138+
editor.OnInspectorGUI();
139+
serializedObject.ApplyModifiedProperties();
140+
});
141+
142+
Object.DestroyImmediate(editor);
143+
return container;
144+
}
145+
}
146+
}

Editor/MotionCollection/MotionCollectionEditor.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Editor/TextEffectEditor.cs renamed to Editor/MotionComponentEditor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
namespace BP.TextMotionProEditor
55
{
6-
[CustomEditor(typeof(TextEffect), true)]
7-
internal class TextEffectEditor : Editor
6+
[CustomEditor(typeof(MotionComponent), editorForChildClasses: true, isFallback = true)]
7+
internal class MotionComponentEditor : Editor
88
{
99
public override void OnInspectorGUI()
1010
{
File renamed without changes.

Editor/MotionEffectRegistry.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using BP.TextMotion;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Reflection;
6+
using UnityEditor;
7+
8+
namespace BP.TextMotionEditor
9+
{
10+
public readonly struct MotionComponentDescriptor
11+
{
12+
public readonly Type Type;
13+
public readonly string DisplayName;
14+
public readonly string Description;
15+
public readonly string Category;
16+
public readonly TextMotionRole Role;
17+
18+
public MotionComponentDescriptor(Type type, string displayName, TextMotionRole role, string description, string category = null)
19+
{
20+
Type = type;
21+
DisplayName = displayName;
22+
Description = description;
23+
Role = role;
24+
Category = category;
25+
}
26+
}
27+
28+
[InitializeOnLoad]
29+
internal static class MotionEffectRegistry
30+
{
31+
public static readonly List<MotionComponentDescriptor> Components = new();
32+
static MotionEffectRegistry() => Init();
33+
34+
public static void Init()
35+
{
36+
Components.Clear();
37+
DiscoverComponents<TagEffect, TextMotionAttribute>();
38+
}
39+
40+
private static void DiscoverComponents<TBase, TAttr>() where TBase : MotionComponent where TAttr : Attribute
41+
{
42+
foreach (var type in GetTypesWithAttribute<TAttr>())
43+
{
44+
if (!typeof(TBase).IsAssignableFrom(type)) continue;
45+
var attr = type.GetCustomAttribute<TAttr>();
46+
if (attr == null) continue;
47+
48+
string name = (string)typeof(TAttr).GetProperty("DisplayName")?.GetValue(attr) ?? type.Name;
49+
string desc = (string)typeof(TAttr).GetProperty("Description")?.GetValue(attr);
50+
string category = (string)typeof(TAttr).GetProperty("Category").GetValue(attr);
51+
TextMotionRole role = (TextMotionRole)typeof(TAttr).GetProperty("Role").GetValue(attr);
52+
Components.Add(new MotionComponentDescriptor(type, name, role, desc, category));
53+
}
54+
}
55+
56+
private static IEnumerable<Type> GetTypesWithAttribute<T>() where T : Attribute
57+
{
58+
return AppDomain.CurrentDomain.GetAssemblies()
59+
.Where(a => !a.IsDynamic && !a.FullName.StartsWith("Unity"))
60+
.SelectMany(a =>
61+
{
62+
try { return a.GetTypes(); }
63+
catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); }
64+
})
65+
.Where(t => t.GetCustomAttribute<T>() != null);
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)