2
2
using System . Collections ;
3
3
using System . Collections . Generic ;
4
4
using System . Collections . Specialized ;
5
- using System . Linq ;
6
- using System . Text ;
5
+ using System . Diagnostics ;
7
6
using UnityEngine ;
8
- using UnityEngine . UI ;
9
7
using UniverseLib ;
10
- using UniverseLib . UI . Widgets ;
11
8
using UniverseLib . UI . Widgets . ScrollView ;
12
9
using UniverseLib . Utility ;
13
10
@@ -24,17 +21,18 @@ public class TransformTree : ICellPoolDataSource<TransformCell>
24
21
/// Key: UnityEngine.Transform instance ID<br/>
25
22
/// Value: CachedTransform
26
23
/// </summary>
27
- internal readonly OrderedDictionary cachedTransforms = new OrderedDictionary ( ) ;
24
+ internal readonly OrderedDictionary cachedTransforms = new ( ) ;
28
25
29
26
// for keeping track of which actual transforms are expanded or not, outside of the cache data.
30
- private readonly HashSet < int > expandedInstanceIDs = new HashSet < int > ( ) ;
31
- private readonly HashSet < int > autoExpandedIDs = new HashSet < int > ( ) ;
27
+ private readonly HashSet < int > expandedInstanceIDs = new ( ) ;
28
+ private readonly HashSet < int > autoExpandedIDs = new ( ) ;
32
29
33
- private readonly HashSet < int > visited = new HashSet < int > ( ) ;
30
+ private readonly HashSet < int > visited = new ( ) ;
34
31
private bool needRefresh ;
35
32
private int displayIndex ;
33
+ int prevDisplayIndex ;
36
34
37
- public int ItemCount => cachedTransforms . Count ;
35
+ public int ItemCount => prevDisplayIndex ;
38
36
39
37
public bool Filtering => ! string . IsNullOrEmpty ( currentFilter ) ;
40
38
private bool wasFiltering ;
@@ -56,45 +54,15 @@ public string CurrentFilter
56
54
}
57
55
private string currentFilter ;
58
56
57
+ private Coroutine refreshCoroutine ;
58
+ private readonly Stopwatch traversedThisFrame = new ( ) ;
59
+
59
60
public TransformTree ( ScrollPool < TransformCell > scrollPool , Func < IEnumerable < GameObject > > getRootEntriesMethod )
60
61
{
61
62
ScrollPool = scrollPool ;
62
63
GetRootEntriesMethod = getRootEntriesMethod ;
63
64
}
64
65
65
- public void OnCellBorrowed ( TransformCell cell )
66
- {
67
- cell . OnExpandToggled += OnCellExpandToggled ;
68
- cell . OnGameObjectClicked += OnGameObjectClicked ;
69
- cell . OnEnableToggled += OnCellEnableToggled ;
70
- }
71
-
72
- private void OnGameObjectClicked ( GameObject obj )
73
- {
74
- if ( OnClickOverrideHandler != null )
75
- OnClickOverrideHandler . Invoke ( obj ) ;
76
- else
77
- InspectorManager . Inspect ( obj ) ;
78
- }
79
-
80
- public void OnCellExpandToggled ( CachedTransform cache )
81
- {
82
- var instanceID = cache . InstanceID ;
83
- if ( expandedInstanceIDs . Contains ( instanceID ) )
84
- expandedInstanceIDs . Remove ( instanceID ) ;
85
- else
86
- expandedInstanceIDs . Add ( instanceID ) ;
87
-
88
- RefreshData ( true ) ;
89
- }
90
-
91
- public void OnCellEnableToggled ( CachedTransform cache )
92
- {
93
- cache . Value . gameObject . SetActive ( ! cache . Value . gameObject . activeSelf ) ;
94
-
95
- RefreshData ( true ) ;
96
- }
97
-
98
66
public void Init ( )
99
67
{
100
68
ScrollPool . Initialize ( this ) ;
@@ -129,7 +97,7 @@ public void JumpAndExpandToTransform(Transform transform)
129
97
}
130
98
131
99
// Refresh cached transforms (no UI rebuild yet)
132
- RefreshData ( false ) ;
100
+ RefreshData ( false , false , false ) ;
133
101
134
102
int transformID = transform . GetInstanceID ( ) ;
135
103
@@ -167,57 +135,82 @@ public void Rebuild()
167
135
autoExpandedIDs . Clear ( ) ;
168
136
expandedInstanceIDs . Clear ( ) ;
169
137
170
- RefreshData ( true , true ) ;
138
+ RefreshData ( true , true , true ) ;
171
139
}
172
140
173
- public void RefreshData ( bool andReload = false , bool jumpToTop = false )
141
+ public void RefreshData ( bool andRefreshUI , bool jumpToTop , bool stopExistingCoroutine )
174
142
{
143
+ if ( refreshCoroutine != null )
144
+ {
145
+ if ( stopExistingCoroutine )
146
+ {
147
+ RuntimeHelper . StopCoroutine ( refreshCoroutine ) ;
148
+ refreshCoroutine = null ;
149
+ }
150
+ else
151
+ return ;
152
+ }
153
+
175
154
visited . Clear ( ) ;
176
155
displayIndex = 0 ;
177
156
needRefresh = false ;
157
+ traversedThisFrame . Reset ( ) ;
158
+ traversedThisFrame . Start ( ) ;
178
159
179
- var rootObjects = GetRootEntriesMethod . Invoke ( ) ;
160
+ IEnumerable < GameObject > rootObjects = GetRootEntriesMethod . Invoke ( ) ;
180
161
181
- //int displayIndex = 0;
182
- foreach ( var obj in rootObjects )
183
- if ( obj ) Traverse ( obj . transform ) ;
162
+ refreshCoroutine = RuntimeHelper . StartCoroutine ( RefreshCoroutine ( rootObjects , andRefreshUI , jumpToTop ) ) ;
163
+ }
164
+
165
+ private IEnumerator RefreshCoroutine ( IEnumerable < GameObject > rootObjects , bool andRefreshUI , bool jumpToTop )
166
+ {
167
+ var thisCoro = refreshCoroutine ;
168
+ foreach ( var gameObj in rootObjects )
169
+ {
170
+ if ( gameObj )
171
+ {
172
+ var enumerator = Traverse ( gameObj . transform ) ;
173
+ while ( enumerator . MoveNext ( ) )
174
+ yield return enumerator . Current ;
175
+ }
176
+ }
184
177
185
178
// Prune displayed transforms that we didnt visit in that traverse
186
179
for ( int i = cachedTransforms . Count - 1 ; i >= 0 ; i -- )
187
180
{
188
- var obj = ( CachedTransform ) cachedTransforms [ i ] ;
189
- if ( ! visited . Contains ( obj . InstanceID ) )
181
+ var cached = ( CachedTransform ) cachedTransforms [ i ] ;
182
+ if ( ! visited . Contains ( cached . InstanceID ) )
190
183
{
191
- cachedTransforms . Remove ( obj . InstanceID ) ;
184
+ cachedTransforms . RemoveAt ( i ) ;
192
185
needRefresh = true ;
193
186
}
194
187
}
195
188
196
- if ( ! needRefresh )
197
- return ;
189
+ if ( andRefreshUI && needRefresh )
190
+ ScrollPool . Refresh ( true , jumpToTop ) ;
198
191
199
- //displayedObjects.Clear();
192
+ prevDisplayIndex = displayIndex ;
193
+ }
200
194
201
- if ( andReload )
195
+ private IEnumerator Traverse ( Transform transform , CachedTransform parent = null , int depth = 0 )
196
+ {
197
+ // Let's only tank 2ms of each frame (60->53fps)
198
+ if ( traversedThisFrame . ElapsedMilliseconds > 2 )
202
199
{
203
- if ( ! jumpToTop )
204
- ScrollPool . Refresh ( true ) ;
205
- else
206
- ScrollPool . Refresh ( true , true ) ;
200
+ yield return null ;
201
+ traversedThisFrame . Reset ( ) ;
202
+ traversedThisFrame . Start ( ) ;
207
203
}
208
- }
209
204
210
- private void Traverse ( Transform transform , CachedTransform parent = null , int depth = 0 )
211
- {
212
205
int instanceID = transform . GetInstanceID ( ) ;
213
206
214
207
if ( visited . Contains ( instanceID ) )
215
- return ;
208
+ yield break ;
216
209
217
210
if ( Filtering )
218
211
{
219
212
if ( ! FilterHierarchy ( transform ) )
220
- return ;
213
+ yield break ;
221
214
222
215
visited . Add ( instanceID ) ;
223
216
@@ -231,8 +224,21 @@ private void Traverse(Transform transform, CachedTransform parent = null, int de
231
224
if ( cachedTransforms . Contains ( instanceID ) )
232
225
{
233
226
cached = ( CachedTransform ) cachedTransforms [ ( object ) instanceID ] ;
227
+ int prevSiblingIdx = cached . SiblingIndex ;
234
228
if ( cached . Update ( transform , depth ) )
229
+ {
235
230
needRefresh = true ;
231
+
232
+ // If the sibling index changed, we need to shuffle it in our cached transforms list.
233
+ if ( prevSiblingIdx != cached . SiblingIndex )
234
+ {
235
+ cachedTransforms . Remove ( instanceID ) ;
236
+ if ( cachedTransforms . Count <= displayIndex )
237
+ cachedTransforms . Add ( instanceID , cached ) ;
238
+ else
239
+ cachedTransforms . Insert ( displayIndex , instanceID , cached ) ;
240
+ }
241
+ }
236
242
}
237
243
else
238
244
{
@@ -249,7 +255,11 @@ private void Traverse(Transform transform, CachedTransform parent = null, int de
249
255
if ( IsCellExpanded ( instanceID ) && cached . Value . childCount > 0 )
250
256
{
251
257
for ( int i = 0 ; i < transform . childCount ; i ++ )
252
- Traverse ( transform . GetChild ( i ) , cached , depth + 1 ) ;
258
+ {
259
+ var enumerator = Traverse ( transform . GetChild ( i ) , cached , depth + 1 ) ;
260
+ while ( enumerator . MoveNext ( ) )
261
+ yield return enumerator . Current ;
262
+ }
253
263
}
254
264
}
255
265
@@ -276,13 +286,44 @@ public void SetCell(TransformCell cell, int index)
276
286
if ( Filtering )
277
287
{
278
288
if ( cell . cachedTransform . Name . ContainsIgnoreCase ( currentFilter ) )
279
- {
280
289
cell . NameButton . ButtonText . color = Color . green ;
281
- }
282
290
}
283
291
}
284
292
else
285
293
cell . Disable ( ) ;
286
294
}
295
+
296
+ public void OnCellBorrowed ( TransformCell cell )
297
+ {
298
+ cell . OnExpandToggled += OnCellExpandToggled ;
299
+ cell . OnGameObjectClicked += OnGameObjectClicked ;
300
+ cell . OnEnableToggled += OnCellEnableToggled ;
301
+ }
302
+
303
+ private void OnGameObjectClicked ( GameObject obj )
304
+ {
305
+ if ( OnClickOverrideHandler != null )
306
+ OnClickOverrideHandler . Invoke ( obj ) ;
307
+ else
308
+ InspectorManager . Inspect ( obj ) ;
309
+ }
310
+
311
+ public void OnCellExpandToggled ( CachedTransform cache )
312
+ {
313
+ var instanceID = cache . InstanceID ;
314
+ if ( expandedInstanceIDs . Contains ( instanceID ) )
315
+ expandedInstanceIDs . Remove ( instanceID ) ;
316
+ else
317
+ expandedInstanceIDs . Add ( instanceID ) ;
318
+
319
+ RefreshData ( true , false , true ) ;
320
+ }
321
+
322
+ public void OnCellEnableToggled ( CachedTransform cache )
323
+ {
324
+ cache . Value . gameObject . SetActive ( ! cache . Value . gameObject . activeSelf ) ;
325
+
326
+ RefreshData ( true , false , true ) ;
327
+ }
287
328
}
288
329
}
0 commit comments