@@ -15,6 +15,15 @@ public abstract class HierarchyPropertyLabel
1515 {
1616 protected GameObject target ;
1717
18+ /// <summary>
19+ /// Does this label draw over the whole item?
20+ /// </summary>
21+ public virtual bool UsesWholeItemRect { get ; } = false ;
22+
23+ /// <summary>
24+ /// Should this label draw for headers too?
25+ /// </summary>
26+ public virtual bool DrawForHeaders { get ; } = false ;
1827
1928 public virtual bool Prepare ( GameObject target , Rect availableRect )
2029 {
@@ -60,6 +69,8 @@ public static HierarchyPropertyLabel GetPropertyLabel(HierarchyItemDataType data
6069 return new HierarchyLayerLabel ( ) ;
6170 case HierarchyItemDataType . Script :
6271 return new HierarchyScriptLabel ( ) ;
72+ case HierarchyItemDataType . TreeLines :
73+ return new HierarchyTreeLinesLabel ( ) ;
6374 }
6475
6576 return null ;
@@ -282,6 +293,164 @@ public override void OnGui(Rect rect)
282293 }
283294 }
284295
296+ private class HierarchyTreeLinesLabel : HierarchyPropertyLabel
297+ {
298+ private List < TreeLineLevelRenderer > levelRenderers = new List < TreeLineLevelRenderer > ( ) ;
299+
300+ private int itemRenderCount = 0 ;
301+
302+ private const float firstElementWidthOffset = 4.0f ;
303+ private const float firstElementXOffset = - 45.0f ;
304+ private const float startXPosition = 30.0f ;
305+ private const float columnSize = 14.0f ;
306+
307+ public override sealed bool UsesWholeItemRect => true ;
308+
309+ public override sealed bool DrawForHeaders => true ;
310+
311+ private bool IsFirstRenderedElement => itemRenderCount == 0 ;
312+
313+ public HierarchyTreeLinesLabel ( )
314+ {
315+ EditorApplication . update += ResetItemRenderCount ;
316+ }
317+
318+ ~ HierarchyTreeLinesLabel ( )
319+ {
320+ EditorApplication . update -= ResetItemRenderCount ;
321+ }
322+
323+ private void ResetItemRenderCount ( )
324+ {
325+ itemRenderCount = 0 ;
326+ }
327+
328+ public override sealed void OnGui ( Rect rect )
329+ {
330+ if ( Event . current . type != EventType . Repaint )
331+ {
332+ return ;
333+ }
334+
335+ int levels = ( int ) ( ( rect . x + firstElementXOffset ) / columnSize ) ;
336+
337+ if ( levels <= 0 )
338+ {
339+ return ;
340+ }
341+
342+ if ( IsFirstRenderedElement )
343+ {
344+ levelRenderers . Clear ( ) ;
345+ }
346+
347+ rect . x = startXPosition ;
348+ rect . width = columnSize + firstElementWidthOffset ;
349+
350+ int siblingIndex = target . transform . GetSiblingIndex ( ) ;
351+
352+ if ( levels > levelRenderers . Count )
353+ {
354+ //Initialize missing tree line level render
355+ int startIndex = levelRenderers . Count ;
356+ int x ;
357+ for ( x = startIndex ; x < levels ; x ++ )
358+ {
359+ var levelRenderer = new TreeLineLevelRenderer ( x + 1 ) ;
360+ levelRenderers . Add ( levelRenderer ) ;
361+ }
362+
363+ x -- ;
364+ Transform transf = target . transform ;
365+
366+ for ( ; x >= startIndex ; x -- )
367+ {
368+ levelRenderers [ x ] . Initialize ( transf ) ;
369+ transf = transf . parent ;
370+ }
371+ }
372+
373+ GUI . color = Color . gray ;
374+
375+ itemRenderCount ++ ;
376+ int i = 0 ;
377+ for ( ; i < ( levels - 1 ) ; i ++ )
378+ {
379+ levelRenderers [ i ] . OnGUI ( rect , target , siblingIndex , false ) ;
380+ rect . x += columnSize ;
381+ }
382+ levelRenderers [ i ] . OnGUI ( rect , target , siblingIndex , true ) ;
383+
384+ GUI . color = Color . white ;
385+ }
386+
387+ private class TreeLineLevelRenderer
388+ {
389+ private bool renderedLastLevelGameobject = false ;
390+ private int level ;
391+
392+ public TreeLineLevelRenderer ( int level )
393+ {
394+ this . level = level ;
395+ }
396+
397+ public void Initialize ( Transform transf )
398+ {
399+ int siblingIndex = transf . GetSiblingIndex ( ) ;
400+ renderedLastLevelGameobject = GetParentChildCount ( transf ) == ( siblingIndex + 1 ) ;
401+ }
402+
403+ public void OnGUI ( Rect rect , GameObject target , int siblingIndex , bool isCurrentLevel )
404+ {
405+ if ( isCurrentLevel )
406+ {
407+ if ( GetParentChildCount ( target ) == ( siblingIndex + 1 ) )
408+ {
409+ renderedLastLevelGameobject = true ;
410+ EditorGUI . LabelField ( rect , "└" , Style . centreAlignTreeLineStyle ) ;
411+ }
412+ else
413+ {
414+ renderedLastLevelGameobject = false ;
415+ EditorGUI . LabelField ( rect , "├" , Style . centreAlignTreeLineStyle ) ;
416+ }
417+ }
418+ else
419+ {
420+ if ( ! renderedLastLevelGameobject )
421+ {
422+ EditorGUI . LabelField ( rect , "│" , Style . centreAlignTreeLineStyle ) ;
423+ }
424+ }
425+ }
426+
427+ private int GetParentChildCount ( Transform target )
428+ {
429+ if ( level == 1 )
430+ {
431+ var scene = target . gameObject . scene ;
432+ return scene . rootCount ;
433+ }
434+ else
435+ {
436+ var parent = target . parent ;
437+ return parent . childCount ;
438+ }
439+ }
440+
441+ private int GetParentChildCount ( GameObject target )
442+ {
443+ var parent = target . transform . parent ;
444+ if ( parent != null )
445+ {
446+ return parent . childCount ;
447+ }
448+
449+ var scene = target . scene ;
450+ return scene . rootCount ;
451+ }
452+ }
453+ }
285454 #endregion
286455
287456 protected static class Style
@@ -292,6 +461,7 @@ protected static class Style
292461 internal static readonly GUIStyle defaultAlignTextStyle ;
293462 internal static readonly GUIStyle centreAlignTextStyle ;
294463 internal static readonly GUIStyle rightAlignTextStyle ;
464+ internal static readonly GUIStyle centreAlignTreeLineStyle ;
295465
296466 static Style ( )
297467 {
@@ -307,28 +477,26 @@ static Style()
307477 {
308478#if UNITY_2019_3_OR_NEWER
309479 fontSize = 9 ,
310- #else
311- fontSize = 8 ,
312- #endif
313- #if UNITY_2019_3_OR_NEWER
314480 alignment = TextAnchor . MiddleCenter
315481#else
482+ fontSize = 8 ,
316483 alignment = TextAnchor . UpperCenter
317484#endif
318485 } ;
319486 rightAlignTextStyle = new GUIStyle ( EditorStyles . miniLabel )
320487 {
321488#if UNITY_2019_3_OR_NEWER
322489 fontSize = 9 ,
323- #else
324- fontSize = 8 ,
325- #endif
326- #if UNITY_2019_3_OR_NEWER
327490 alignment = TextAnchor . MiddleRight
328491#else
492+ fontSize = 8 ,
329493 alignment = TextAnchor . UpperRight
330494#endif
331495 } ;
496+ centreAlignTreeLineStyle = new GUIStyle ( EditorStyles . miniLabel )
497+ {
498+ fontSize = 18 ,
499+ } ;
332500 }
333501 }
334502 }
0 commit comments