2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
4
using System . Reflection ;
5
+ using UnityEditor ;
5
6
using UnityEditor . IMGUI . Controls ;
6
7
using UnityEngine ;
7
8
using Object = UnityEngine . Object ;
@@ -16,22 +17,38 @@ public sealed class CollectionItemDropdown : AdvancedDropdown
16
17
17
18
private readonly Type itemType ;
18
19
private readonly SOCItemEditorOptionsAttribute options ;
19
- private readonly Object owner ;
20
+ private readonly SerializedProperty serializedProperty ;
20
21
private readonly MethodInfo validationMethod ;
22
+
23
+ private readonly MethodInfo onSelectCallbackMethod ;
21
24
22
25
public CollectionItemDropdown ( AdvancedDropdownState state , Type targetItemType ,
23
- SOCItemEditorOptionsAttribute options , Object owner ) : base ( state )
26
+ SOCItemEditorOptionsAttribute options , SerializedProperty serializedProperty ) : base ( state )
24
27
{
25
28
itemType = targetItemType ;
26
29
collections = CollectionsRegistry . Instance . GetCollectionsByItemType ( itemType ) ;
27
30
minimumSize = new Vector2 ( 200 , 300 ) ;
28
31
this . options = options ;
29
- this . owner = owner ;
32
+ this . serializedProperty = serializedProperty ;
30
33
31
-
32
- if ( options != null && ! string . IsNullOrEmpty ( options . ValidateMethod ) )
34
+ if ( options != null )
33
35
{
34
- validationMethod = owner . GetType ( ) . GetMethod ( options . ValidateMethod , new [ ] { itemType } ) ;
36
+ Object owner = serializedProperty . serializedObject . targetObject ;
37
+ if ( ! string . IsNullOrEmpty ( options . ValidateMethod ) )
38
+ validationMethod = owner . GetType ( ) . GetMethod ( options . ValidateMethod , new [ ] { itemType } ) ;
39
+
40
+ // If it's specified that a callback should be fired when an item is selected, cache that callback.
41
+ if ( ! string . IsNullOrEmpty ( options . OnSelectCallbackMethod ) )
42
+ {
43
+ onSelectCallbackMethod = owner . GetType ( ) . GetMethod ( options . OnSelectCallbackMethod ,
44
+ BindingFlags . Instance | BindingFlags . Static | BindingFlags . Public | BindingFlags . NonPublic ,
45
+ null , new [ ] { itemType , itemType } , null ) ;
46
+ if ( onSelectCallbackMethod == null )
47
+ {
48
+ Debug . LogWarning ( $ "Component '{ owner . name } ' wants selection callback " +
49
+ $ "'{ options . OnSelectCallbackMethod } ' which is not a valid method.") ;
50
+ }
51
+ }
35
52
}
36
53
}
37
54
@@ -42,19 +59,49 @@ protected override AdvancedDropdownItem BuildRoot()
42
59
root . AddChild ( new AdvancedDropdownItem ( "None" ) ) ;
43
60
root . AddSeparator ( ) ;
44
61
62
+ // If specified, limit the displayed items to those of a collection specified in a certain field.
63
+ ScriptableObjectCollection collectionToConstrainTo = null ;
64
+ if ( ! string . IsNullOrEmpty ( options . ConstrainToCollectionField ) )
65
+ {
66
+ SerializedProperty collectionField = serializedProperty . serializedObject . FindProperty (
67
+ options . ConstrainToCollectionField ) ;
68
+ if ( collectionField == null )
69
+ {
70
+ Debug . LogWarning ( $ "Tried to constrain dropdown to collection specified in field " +
71
+ $ "'{ options . ConstrainToCollectionField } ' but no such field existed in " +
72
+ $ "'{ serializedProperty . serializedObject . targetObject } '") ;
73
+ return root ;
74
+ }
75
+
76
+ collectionToConstrainTo = collectionField . objectReferenceValue as ScriptableObjectCollection ;
77
+ if ( collectionToConstrainTo == null )
78
+ {
79
+ Debug . LogWarning ( $ "Tried to constrain dropdown to collection specified in field " +
80
+ $ "'{ options . ConstrainToCollectionField } ' but no collection was specified.") ;
81
+ return root ;
82
+ }
83
+ }
84
+ bool shouldConstrainToCollection = collectionToConstrainTo != null ;
85
+
45
86
AdvancedDropdownItem targetParent = root ;
46
87
bool multipleCollections = collections . Count > 1 ;
47
88
for ( int i = 0 ; i < collections . Count ; i ++ )
48
89
{
49
90
ScriptableObjectCollection collection = collections [ i ] ;
91
+
92
+ // If we're meant to constrain the selection to a specific collection, enforce that now.
93
+ if ( shouldConstrainToCollection && collectionToConstrainTo != collection )
94
+ continue ;
50
95
51
- if ( multipleCollections )
96
+ // If there are multiple collections, group them together.
97
+ if ( multipleCollections && ! shouldConstrainToCollection )
52
98
{
53
99
AdvancedDropdownItem collectionParent = new AdvancedDropdownItem ( collection . name ) ;
54
100
root . AddChild ( collectionParent ) ;
55
101
targetParent = collectionParent ;
56
102
}
57
103
104
+ // Add every individual item in the collection.
58
105
for ( int j = 0 ; j < collection . Count ; j ++ )
59
106
{
60
107
ScriptableObject collectionItem = collection [ j ] ;
@@ -64,11 +111,12 @@ protected override AdvancedDropdownItem BuildRoot()
64
111
65
112
if ( validationMethod != null )
66
113
{
67
- bool result = ( bool ) validationMethod . Invoke ( owner , new object [ ] { collectionItem } ) ;
114
+ bool result = ( bool ) validationMethod . Invoke (
115
+ serializedProperty . serializedObject . targetObject , new object [ ] { collectionItem } ) ;
68
116
if ( ! result )
69
117
continue ;
70
118
}
71
-
119
+
72
120
targetParent . AddChild ( new CollectionItemDropdownItem ( collectionItem ) ) ;
73
121
}
74
122
}
@@ -81,22 +129,57 @@ protected override AdvancedDropdownItem BuildRoot()
81
129
return root ;
82
130
}
83
131
132
+ private void InvokeOnSelectCallback ( ScriptableObject from , ScriptableObject to )
133
+ {
134
+ if ( onSelectCallbackMethod == null )
135
+ return ;
136
+
137
+ object [ ] arguments = { from , to } ;
138
+
139
+ // The method may be static, in which case there is no target.
140
+ if ( onSelectCallbackMethod . IsStatic )
141
+ {
142
+ onSelectCallbackMethod . Invoke ( null , arguments ) ;
143
+ return ;
144
+ }
145
+
146
+ // Otherwise, fire the callback on every target.
147
+ for ( int i = 0 ; i < serializedProperty . serializedObject . targetObjects . Length ; i ++ )
148
+ {
149
+ object target = serializedProperty . serializedObject . targetObjects [ i ] ;
150
+ onSelectCallbackMethod . Invoke ( target , arguments ) ;
151
+ }
152
+ }
153
+
84
154
protected override void ItemSelected ( AdvancedDropdownItem item )
85
155
{
86
156
base . ItemSelected ( item ) ;
87
157
158
+ ScriptableObject previousValue = null ;
159
+ if ( onSelectCallbackMethod != null )
160
+ previousValue = serializedProperty . objectReferenceValue as ScriptableObject ;
161
+
88
162
if ( item . name . Equals ( CREATE_NEW_TEXT , StringComparison . OrdinalIgnoreCase ) )
89
163
{
90
164
ScriptableObjectCollection collection = collections . First ( ) ;
91
165
ScriptableObject newItem = CollectionCustomEditor . AddNewItem ( collection , itemType ) ;
92
166
callback . Invoke ( newItem ) ;
167
+
168
+ InvokeOnSelectCallback ( previousValue , newItem ) ;
169
+
93
170
return ;
94
171
}
95
172
96
173
if ( item is CollectionItemDropdownItem dropdownItem )
174
+ {
97
175
callback . Invoke ( dropdownItem . CollectionItem ) ;
176
+ InvokeOnSelectCallback ( previousValue , dropdownItem . CollectionItem ) ;
177
+ }
98
178
else
179
+ {
99
180
callback . Invoke ( null ) ;
181
+ InvokeOnSelectCallback ( previousValue , null ) ;
182
+ }
100
183
}
101
184
102
185
public void Show ( Rect rect , Action < ScriptableObject > onSelectedCallback )
0 commit comments