Skip to content

Commit 140ae8f

Browse files
authored
Merge pull request #16 from TarasK8/feature/state-machine-improvment
StateMachine improvments
2 parents ae4639f + d04d778 commit 140ae8f

File tree

7 files changed

+219
-43
lines changed

7 files changed

+219
-43
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using System;
2+
using UnityEditor.IMGUI.Controls;
3+
using UnityEngine;
4+
using System.Collections.Generic;
5+
6+
namespace TarasK8.UI.Editor.Animations
7+
{
8+
public class AnimatedPropertiesDropdown : AdvancedDropdown
9+
{
10+
private readonly string[] _properties;
11+
private readonly Dictionary<AdvancedDropdownItem, string> _itemToPathMap;
12+
private readonly Dictionary<string, int> _propertyIndexMap;
13+
14+
public Action<int> OnItemSelected { get; set; }
15+
16+
public AnimatedPropertiesDropdown(AdvancedDropdownState state, string[] properties) : base(state)
17+
{
18+
_properties = properties;
19+
minimumSize = new Vector2(200f, 300f);
20+
21+
// Initialize lookup dictionaries
22+
_itemToPathMap = new Dictionary<AdvancedDropdownItem, string>();
23+
_propertyIndexMap = BuildPropertyIndexMap(properties);
24+
}
25+
26+
protected override AdvancedDropdownItem BuildRoot()
27+
{
28+
var root = new AdvancedDropdownItem("Properties");
29+
30+
// Build the tree from the string array
31+
var categoryTree = BuildCategoryTree(_properties);
32+
33+
// Convert the tree into AdvancedDropdownItems
34+
foreach (var category in categoryTree)
35+
{
36+
AddCategoryToDropdown(root, category.Key, category.Value, category.Key);
37+
}
38+
39+
return root;
40+
}
41+
42+
private Dictionary<string, object> BuildCategoryTree(string[] properties)
43+
{
44+
var root = new Dictionary<string, object>();
45+
46+
foreach (var property in properties)
47+
{
48+
var parts = property.Split('/');
49+
var currentNode = root;
50+
51+
for (int i = 0; i < parts.Length; i++)
52+
{
53+
if (!currentNode.ContainsKey(parts[i]))
54+
{
55+
currentNode[parts[i]] = new Dictionary<string, object>();
56+
}
57+
58+
// Navigate to the next level
59+
currentNode = (Dictionary<string, object>)currentNode[parts[i]];
60+
}
61+
}
62+
63+
return root;
64+
}
65+
66+
private void AddCategoryToDropdown(AdvancedDropdownItem parent, string categoryName, object subcategories, string fullPath)
67+
{
68+
var categoryItem = new AdvancedDropdownItem(categoryName);
69+
70+
// Store the full path for this item
71+
_itemToPathMap[categoryItem] = fullPath;
72+
73+
parent.AddChild(categoryItem);
74+
75+
if (subcategories is Dictionary<string, object> subcategoryDict)
76+
{
77+
foreach (var subcategory in subcategoryDict)
78+
{
79+
var childFullPath = $"{fullPath}/{subcategory.Key}";
80+
AddCategoryToDropdown(categoryItem, subcategory.Key, subcategory.Value, childFullPath);
81+
}
82+
}
83+
}
84+
85+
private Dictionary<string, int> BuildPropertyIndexMap(string[] properties)
86+
{
87+
var map = new Dictionary<string, int>();
88+
for (int i = 0; i < properties.Length; i++)
89+
{
90+
map[properties[i]] = i;
91+
}
92+
return map;
93+
}
94+
95+
protected override void ItemSelected(AdvancedDropdownItem item)
96+
{
97+
base.ItemSelected(item);
98+
99+
// Lookup the full path of the selected item
100+
if (_itemToPathMap.TryGetValue(item, out string selectedProperty))
101+
{
102+
if (_propertyIndexMap.TryGetValue(selectedProperty, out int index))
103+
{
104+
OnItemSelected?.Invoke(index); // Raise the event with the index
105+
}
106+
else
107+
{
108+
Debug.LogWarning($"Selected item '{selectedProperty}' not found in the properties array.");
109+
}
110+
}
111+
else
112+
{
113+
Debug.LogWarning("Selected item not mapped to a property.");
114+
}
115+
}
116+
}
117+
}

Editor/Animations/AnimatedPropertiesDropdown.cs.meta

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

Editor/Animations/StateListDrawer.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ public static class StateListDrawer
1111
{
1212
public const string NameFieldName = "<Name>k__BackingField";
1313

14-
public static void Draw(SerializedProperty property, StateList stateList)
14+
public static void Draw(SerializedProperty property)
1515
{
1616
var listProperty = property.FindPropertyRelative("_states");
17-
18-
EditorGUILayout.LabelField($"States ({stateList.Count})", EditorStyles.boldLabel);
1917

2018
for (int i = 0; i < listProperty.arraySize; i++)
2119
{

Editor/Animations/StateMachineEditor.cs

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using TarasK8.UI.Animations.AnimatedProperties;
77
using TarasK8.UI.Editor.Utils;
88
using UnityEditor;
9+
using UnityEditor.IMGUI.Controls;
910
using UnityEngine;
1011

1112
namespace TarasK8.UI.Editor.Animations
@@ -16,14 +17,18 @@ public class StateMachineEditor : UnityEditor.Editor
1617
{
1718
private static string[] _propertiesTypesOptions;
1819
private static List<Type> _propertiesTypes;
20+
private static AnimatedPropertiesDropdown _addPropertyDropdown;
1921
private int _selectedTypeOption;
2022
private string _selectedStateName;
2123
private SerializedProperty _ignoreTimeScale;
2224
private SerializedProperty _fullyComplete;
2325
private SerializedProperty _defaultState;
2426
private SerializedProperty _animatedProperties;
25-
private StateMachine _target;
2627
private SerializedProperty _states;
28+
private static bool _showProperties = true;
29+
private static bool _showStates = true;
30+
31+
private StateMachine _target;
2732

2833
private void OnEnable()
2934
{
@@ -43,27 +48,46 @@ private void OnEnable()
4348
for (int i = 0; i < _propertiesTypes.Count; i++)
4449
{
4550
TransitionMenuNameAttribute attribute = (TransitionMenuNameAttribute)Attribute.GetCustomAttribute(_propertiesTypes[i], typeof(TransitionMenuNameAttribute));
46-
_propertiesTypesOptions[i] = attribute?.MenuName ?? _propertiesTypes[i].Name;
51+
string option = attribute?.MenuName ?? _propertiesTypes[i].Name;
52+
_propertiesTypesOptions[i] = option;
4753
}
54+
var state = new AdvancedDropdownState();
55+
_addPropertyDropdown = new AnimatedPropertiesDropdown(state, _propertiesTypesOptions);
4856
}
57+
_showProperties = EditorPrefs.GetBool(nameof(_showProperties), _showProperties);
58+
}
59+
60+
private void OnDisable()
61+
{
62+
EditorPrefs.SetBool(nameof(_showProperties), _showProperties);
4963
}
5064

5165
public override void OnInspectorGUI()
5266
{
5367
serializedObject.Update();
5468

5569
DrawOptions();
56-
EditorGUILayout.Space(15f);
5770

58-
DrawLabel();
59-
_selectedTypeOption = EditorGUILayout.Popup(_selectedTypeOption, _propertiesTypesOptions);
60-
DrawAllAnimatedProperties();
61-
DrawAddPropertyButton();
62-
EditorGUILayout.Space(15f);
63-
StateListDrawer.Draw(_states, _target.States);
64-
DrawAddStateButton();
71+
EditorGUILayout.Space();
72+
73+
_showProperties = EditorGUILayout.BeginFoldoutHeaderGroup(_showProperties,
74+
$"Animated Properties ({_animatedProperties.arraySize})");
75+
if (_showProperties)
76+
{
77+
DrawAllAnimatedProperties();
78+
DrawAddPropertyButton();
79+
}
80+
EditorGUILayout.EndFoldoutHeaderGroup();
6581

66-
//DrawAllStates();
82+
EditorGUILayout.Space();
83+
84+
_showStates = EditorGUILayout.BeginFoldoutHeaderGroup(_showStates, $"States ({_target.States.Count})");
85+
if (_showStates)
86+
{
87+
StateListDrawer.Draw(_states);
88+
DrawAddStateButton();
89+
}
90+
EditorGUILayout.EndFoldoutHeaderGroup();
6791

6892
serializedObject.ApplyModifiedProperties();
6993
}
@@ -82,50 +106,65 @@ private void DrawAllAnimatedProperties()
82106
EditorGUILayout.BeginVertical(GUI.skin.box);
83107

84108
var animatedProperty = _animatedProperties.GetArrayElementAtIndex(i);
109+
var childs = animatedProperty.GetChildProperties().ToArray();
110+
85111
EditorGUILayout.BeginHorizontal();
112+
EditorGUILayout.PropertyField(childs[0], GUIContent.none, GUILayout.Width(16f));
86113
EditorGUILayout.LabelField(animatedProperty.managedReferenceValue.GetType().Name, EditorStyles.boldLabel);
87114
if (MyGuiUtility.DrawRemoveButton())
88115
{
89-
_target.RemoveAnimatedProperty(i);
90-
EditorUtility.SetDirty(target);
116+
foreach (var target in targets)
117+
{
118+
var stateMachine = target as StateMachine;
119+
stateMachine.RemoveAnimatedProperty(i);
120+
EditorUtility.SetDirty(stateMachine);
121+
}
91122
}
92-
EditorGUILayout.EndHorizontal();
93123

94-
var childs = animatedProperty.GetChildProperties();
95-
foreach (var element in childs)
124+
EditorGUILayout.EndHorizontal();
125+
for (int j = 1; j < childs.Length; j++)
96126
{
97-
127+
var element = childs[j];
98128
EditorGUILayout.PropertyField(element);
99129
}
130+
100131
EditorGUILayout.EndVertical();
101132
}
102133
}
103-
104-
private void DrawLabel()
105-
{
106-
EditorGUILayout.BeginHorizontal();
107-
EditorGUILayout.LabelField($"Animated Properties ({_animatedProperties.arraySize})", EditorStyles.boldLabel);
108-
EditorGUILayout.EndHorizontal();
109-
}
110134

111-
public void DrawAddPropertyButton()
135+
private void DrawAddPropertyButton()
112136
{
137+
var lastRect = GUILayoutUtility.GetLastRect();
113138
if (MyGuiUtility.DrawAddButton("Add Animated Property"))
114139
{
115-
var type = _propertiesTypes[_selectedTypeOption];
116-
AnimatedProperty animatedProperty = (AnimatedProperty)Activator.CreateInstance(type);
117-
_target.AddAnimatedProperty(animatedProperty);
118-
EditorUtility.SetDirty(target);
140+
_addPropertyDropdown.OnItemSelected = AddProperty;
141+
_addPropertyDropdown.Show(CalculateDropdownRect(lastRect));
119142
}
120143
}
121144

122-
public void DrawAddStateButton()
145+
private void DrawAddStateButton()
123146
{
124147
if (MyGuiUtility.DrawAddButton("Add State"))
125148
{
126-
var name = StateListDrawer.GetUniqueName(_target.States);
127-
_target.AddState(name);
128-
EditorUtility.SetDirty(serializedObject.targetObject);
149+
foreach (var target in targets)
150+
{
151+
var stateMachine = target as StateMachine;
152+
var name = StateListDrawer.GetUniqueName(stateMachine.States);
153+
stateMachine.AddState(name);
154+
EditorUtility.SetDirty(stateMachine);
155+
}
156+
}
157+
}
158+
159+
private void AddProperty(int index)
160+
{
161+
var type = _propertiesTypes[index];
162+
AnimatedProperty animatedProperty = (AnimatedProperty)Activator.CreateInstance(type);
163+
foreach (var target in targets)
164+
{
165+
var stateMachine = target as StateMachine;
166+
stateMachine.AddAnimatedProperty(animatedProperty);
167+
EditorUtility.SetDirty(stateMachine);
129168
}
130169
}
131170

@@ -142,5 +181,18 @@ private List<Type> GetAnimatedPropertyTypes()
142181
}
143182
return derivedTypes;
144183
}
184+
185+
private Rect CalculateDropdownRect(Rect lastRect)
186+
{
187+
const float width = 230f;
188+
const float buttonSpacing = 27f;
189+
const float xOffset = 18f;
190+
191+
float x = (lastRect.width - width) * 0.5f + xOffset;
192+
float y = lastRect.y + buttonSpacing;
193+
var rect = new Rect(x, y, width, lastRect.height);
194+
195+
return rect;
196+
}
145197
}
146198
}

Runtime/Animations/AnimatedProperties/AnimatedProperty.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ namespace TarasK8.UI.Animations.AnimatedProperties
99
[Serializable]
1010
public abstract class AnimatedProperty : Tween
1111
{
12+
[SerializeField] private bool _enabled = true;
13+
14+
public bool Enabled { get => _enabled; set => _enabled = value; }
15+
1216
public abstract void SetAnimationData(IAnimationData data);
1317

1418
public abstract IAnimationData CreateNewAnimationData();
@@ -18,21 +22,21 @@ public abstract class AnimatedProperty : Tween
1822
public abstract class AnimatedProperty<T> : AnimatedProperty
1923
where T : IAnimationData, new()
2024
{
21-
private T _data;
25+
private T _animData;
2226

23-
public override void SetAnimationData(IAnimationData data)
27+
public sealed override void SetAnimationData(IAnimationData data)
2428
{
25-
_data = (T)data;
29+
_animData = (T)data;
2630
}
2731

28-
public override IAnimationData CreateNewAnimationData()
32+
public sealed override IAnimationData CreateNewAnimationData()
2933
{
3034
return new T();
3135
}
3236

33-
public override void Start()
37+
public sealed override void Start()
3438
{
35-
Start(_data);
39+
Start(_animData);
3640
}
3741

3842
public abstract void Start(T data);

Runtime/Animations/StateMachine.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ private void SetState(int stateIndex, bool instantly)
9090
for (int i = 0; i < _animatedProperties.Count; i++)
9191
{
9292
var animatedProperty = _animatedProperties[i];
93+
if(animatedProperty.Enabled == false)
94+
continue;
9395
animatedProperty.SetAnimationData(_states.GetAnimationData(stateIndex, i));
9496
if (animatedProperty.IsStarted && _fullyCompleteTransition)
9597
animatedProperty.Process(1f);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.tarask8.optimized-ui",
3-
"version": "0.2.2",
3+
"version": "0.2.3",
44
"displayName": "Optimized UI",
55
"description": "A package for Unity that is designed to greatly simplify user interface development.",
66
"unity": "2022.3",

0 commit comments

Comments
 (0)