{"TotalCount":2,"Files":[{"Ident":"yugi.hierarchychanges","Path":"Editor/HierarchyColoursDock.cs","FileName":"HierarchyColoursDock.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":381874,"Code":"using System;\nusing System.IO;\nusing System.Text.Json;\nusing Editor;\nusing Sandbox;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace HierarchyChanges;\n\n\n/// \u003Csummary\u003EPrototype palette for editor-only annotations on the stock hierarchy.\u003C/summary\u003E\n[Dock( \u0022Editor\u0022, \u0022Hierarchy Changes\u0022, \u0022palette\u0022, DockArea.Right )]\npublic sealed class HierarchyColoursDock : Widget\n{\n\tprivate readonly Label status;\n\n\tpublic HierarchyColoursDock( Widget parent ) : base( parent )\n\t{\n\t\tLayout = Layout.Column();\n\t\tLayout.Margin = 8;\n\t\tLayout.Spacing = 6;\n\t\tLayout.Add( new Label( \u0022Select objects in the hierarchy, then choose a colour.\u0022, this ) );\n\t\tLayout.Add( new Label( \u0022Middle-click a hierarchy row to expand or collapse it.\u0022, this ) );\n\t\tfor ( var i = 0; i \u003C HierarchyColourPreview.Colours.Length; i\u002B\u002B )\n\t\t{\n\t\t\tvar index = i;\n\t\t\tvar button = Layout.Add( new Button( HierarchyColourPreview.Names[i], this ) );\n\t\t\tbutton.SetStyles( $\u0022background-color: {HierarchyColourPreview.Css[i]}; color: white;\u0022 );\n\t\t\tbutton.Clicked \u002B= () =\u003E HierarchyColourPreview.Assign( index );\n\t\t}\n\t\tLayout.Add( new Button( \u0022Clear selected colours\u0022, this ) ).Clicked \u002B= () =\u003E HierarchyColourPreview.Assign( -1 );\n\t\tLayout.Add( new Button( \u0022Make selected names bold\u0022, this ) ).Clicked \u002B= () =\u003E HierarchyColourPreview.SetBold( true );\n\t\tLayout.Add( new Button( \u0022Use regular names\u0022, this ) ).Clicked \u002B= () =\u003E HierarchyColourPreview.SetBold( false );\n\t\tLayout.Add( new Button( \u0022Toggle colour preview\u0022, this ) ).Clicked \u002B= HierarchyColourPreview.Toggle;\n\t\tstatus = Layout.Add( new Label( \u0022\u0022, this ) );\n\t\tLayout.AddStretchCell();\n\t}\n\n\t[EditorEvent.Frame]\n\tprivate void RefreshStatus()\n\t{\n\t\tstatus.Text = HierarchyColourPreview.Status;\n\t}\n}\n\n/// \u003Csummary\u003E\n/// Adds colour underlays and dispatches bold rows while retaining stock interaction.\n/// This remains independent of game code so it can move into a library\u0027s Editor folder.\n/// \u003C/summary\u003E\ninternal static class HierarchyColourPreview\n{\n\tinternal static readonly string[] Names = [\u0022Red\u0022, \u0022Orange\u0022, \u0022Yellow\u0022, \u0022Green\u0022, \u0022Blue\u0022, \u0022Purple\u0022];\n\tinternal static readonly string[] Css = [\u0022#873b42\u0022, \u0022#875331\u0022, \u0022#756725\u0022, \u0022#346849\u0022, \u0022#365f87\u0022, \u0022#694482\u0022];\n\tinternal static readonly Color[] Colours =\n\t[\n\t\tnew( 0.85f, 0.25f, 0.30f ), new( 0.95f, 0.48f, 0.18f ), new( 0.90f, 0.78f, 0.20f ),\n\t\tnew( 0.25f, 0.75f, 0.40f ), new( 0.25f, 0.55f, 0.95f ), new( 0.68f, 0.35f, 0.90f )\n\t];\n\tprivate static Dictionary\u003Cstring, int\u003E assignments = new();\n\t// Preserve the original 0..5 colour values. Bits 0..2 hold colour (7 = none);\n\t// bit 3 stores bold independently, so clearing colour never clears emphasis.\n\tprivate const int NoColour = 7;\n\tprivate const int BoldFlag = 8;\n\tprivate static TreeView tree;\n\tprivate static TreeView inputTree;\n\tprivate static Func\u003Cbool\u003E previousPaint;\n\tprivate static bool enabled = true;\n\tprivate static string settingsPath;\n\tprivate static bool storageAvailable;\n\tprivate static string error;\n\tinternal static string Status =\u003E error ?? (enabled ? \u0022Preview on \u00B7 colours and bold save automatically.\u0022 : \u0022Preview off \u00B7 saved styles retained.\u0022);\n\n\t// The hook also runs when the palette is hidden. It reconnects when the hierarchy is rebuilt.\n\t[EditorEvent.Frame]\n\tprivate static void Frame()\n\t{\n\t\tLoadProject();\n\t\tvar current = SceneTreeWidget.Current?.TreeView;\n\t\tAttachMiddleClick( current is not null \u0026\u0026 current.IsValid() ? current : null );\n\t\tif ( !enabled || current is null || !current.IsValid() )\n\t\t{\n\t\t\tDetach();\n\t\t\treturn;\n\t\t}\n\t\tif ( ReferenceEquals( tree, current ) ) return;\n\t\tDetach();\n\t\ttree = current;\n\t\tpreviousPaint = tree.OnPaintOverride;\n\t\ttree.OnPaintOverride = PaintUnderlay;\n\t\ttree.Update();\n\t}\n\n\t[EditorEvent.Hotload]\n\tprivate static void Hotload()\n\t{\n\t\tDetach();\n\t\tAttachMiddleClick( null );\n\t}\n\n\tprivate static void AttachMiddleClick( TreeView current )\n\t{\n\t\tif ( ReferenceEquals( inputTree, current ) ) return;\n\t\t// Input stays active with colour preview off; remove only our own subscription.\n\t\tif ( inputTree is not null \u0026\u0026 inputTree.IsValid() ) inputTree.MouseMiddlePress -= MiddleClick;\n\t\tinputTree = current;\n\t\tif ( inputTree is not null ) inputTree.MouseMiddlePress \u002B= MiddleClick;\n\t}\n\n\tprivate static void MiddleClick()\n\t{\n\t\tif ( inputTree is null || !inputTree.IsValid() ) return;\n\t\tvar item = inputTree.GetItemAt( inputTree.FromScreen( Editor.Application.CursorPosition ) );\n\t\tif ( item is null || !item.HasChildren || item.Object is not TreeNode node\n\t\t\t|| node.ExpanderHidden || node.Value is not GameObject go || !go.IsValid() ) return;\n\t\t// Toggle only this branch, preserving descendant expansion state and selection.\n\t\tinputTree.Toggle( go );\n\t\tinputTree.Update();\n\t}\n\n\tprivate static void Detach()\n\t{\n\t\t// Restore only our own callback; don\u0027t erase another extension\u0027s later replacement.\n\t\tif ( tree is not null \u0026\u0026 tree.IsValid() \u0026\u0026 tree.OnPaintOverride == PaintUnderlay )\n\t\t{\n\t\t\ttree.OnPaintOverride = previousPaint;\n\t\t\ttree.Update();\n\t\t}\n\t\ttree = null;\n\t\tpreviousPaint = null;\n\t}\n\n\tinternal static void Toggle()\n\t{\n\t\tenabled = !enabled;\n\t\tFrame();\n\t}\n\n\tprivate static string Key( GameObject go ) =\u003E $\u0022{go.Scene.Id:N}/{go.Id:N}\u0022;\n\n\tinternal static void Assign( int colour )\n\t\t=\u003E EditSelected( value =\u003E (value \u0026 BoldFlag) | (colour \u003C 0 ? NoColour : colour) );\n\n\tinternal static void SetBold( bool bold )\n\t\t=\u003E EditSelected( value =\u003E bold ? value | BoldFlag : value \u0026 ~BoldFlag );\n\n\tprivate static void EditSelected( Func\u003Cint, int\u003E edit )\n\t{\n\t\tLoadProject();\n\t\tif ( !storageAvailable ) return;\n\t\tvar scene = SceneEditorSession.Active?.Scene;\n\t\tif ( scene is null || !scene.IsEditor ) return;\n\t\tvar selected = SceneEditorSession.Active.Selection.OfType\u003CGameObject\u003E().Where( go =\u003E go.IsValid() \u0026\u0026 go.Scene == scene ).ToArray();\n\t\tif ( selected.Length == 0 ) return;\n\t\tvar next = new Dictionary\u003Cstring, int\u003E( assignments );\n\t\tforeach ( var go in selected )\n\t\t{\n\t\t\tvar key = Key( go );\n\t\t\tvar value = edit( next.GetValueOrDefault( key, NoColour ) );\n\t\t\tif ( value == NoColour ) next.Remove( key );\n\t\t\telse next[key] = value;\n\t\t}\n\t\ttry\n\t\t{\n\t\t\tDirectory.CreateDirectory( Path.GetDirectoryName( settingsPath ) );\n\t\t\tvar temporary = settingsPath \u002B \u0022.tmp\u0022;\n\t\t\tFile.WriteAllText( temporary, JsonSerializer.Serialize( next, new JsonSerializerOptions { WriteIndented = true } ) );\n\t\t\tFile.Move( temporary, settingsPath, true );\n\t\t\tassignments = next;\n\t\t\terror = null;\n\t\t\ttree?.Update();\n\t\t}\n\t\tcatch ( Exception e ) { error = $\u0022Could not save colours: {e.Message}\u0022; }\n\t}\n\n\tprivate static void LoadProject()\n\t{\n\t\tvar root = Project.Current?.RootDirectory?.FullName;\n\t\tvar path = root is null ? null : Path.Combine( root, \u0022Settings\u0022, \u0022hierarchy-colours.json\u0022 );\n\t\tif ( settingsPath == path ) return;\n\t\tsettingsPath = path;\n\t\tassignments = new();\n\t\tstorageAvailable = path is not null;\n\t\terror = null;\n\t\ttry\n\t\t{\n\t\t\tif ( path is not null \u0026\u0026 File.Exists( path ) )\n\t\t\t\tassignments = JsonSerializer.Deserialize\u003CDictionary\u003Cstring, int\u003E\u003E( File.ReadAllText( path ) ) ?? new();\n\t\t}\n\t\tcatch ( Exception e )\n\t\t{\n\t\t\t// Never overwrite unreadable settings with an empty palette.\n\t\t\tstorageAvailable = false;\n\t\t\terror = $\u0022Could not load colours: {e.Message}\u0022;\n\t\t}\n\t}\n\n\tprivate static bool PaintUnderlay()\n\t{\n\t\tif ( previousPaint?.Invoke() == true ) return true;\n\t\tvar scene = SceneEditorSession.Active?.Scene;\n\t\tif ( scene is null || !scene.IsEditor || assignments.Count == 0 ) return false;\n\t\t// ItemLayouts is protected. Public hit-testing discovers only visible rows, then\n\t\t// jumps to each row\u0027s bottom; it does not traverse every object in a large scene.\n\t\tvar x = Math.Max( tree.Margin.Left \u002B 1, tree.Width * 0.5f );\n\t\tvar rows = new List\u003CVirtualWidget\u003E();\n\t\tvar hasBold = false;\n\t\tfor ( float y = 0; y \u003C tree.Height; )\n\t\t{\n\t\t\tvar item = tree.GetItemAt( new Vector2( x, y ) );\n\t\t\tif ( item is null ) { y \u002B= 1; continue; }\n\t\t\ty = Math.Max( y \u002B 1, item.Rect.Bottom \u002B 0.5f );\n\t\t\trows.Add( item );\n\t\t\tif ( item.Object is not TreeNode node || node.Value is not GameObject go || !go.IsValid() ) continue;\n\t\t\tif ( !assignments.TryGetValue( Key( go ), out var style ) ) continue;\n\t\t\thasBold |= (style \u0026 BoldFlag) != 0;\n\t\t\tvar index = style \u0026 NoColour;\n\t\t\tif ( index \u003E= Colours.Length ) continue;\n\t\t\tvar rect = item.Rect;\n\t\t\trect.Left = 0;\n\t\t\trect.Right = tree.Width;\n\t\t\tPaint.ClearPen();\n\t\t\tPaint.SetBrush( Colours[index].WithAlpha( go.Active ? 0.24f : 0.10f ) );\n\t\t\tPaint.DrawRect( rect );\n\t\t}\n\t\tif ( !hasBold ) return false;\n\t\t// Stock GameObjectNode hardcodes font weight. When bold is visible, dispatch\n\t\t// rows ourselves, preserving the actual nodes for selection, drag and rename.\n\t\tPaint.Antialiasing = true;\n\t\tPaint.TextAntialiasing = true;\n\t\tforeach ( var item in rows ) PaintRow( item );\n\t\treturn true;\n\t}\n\n\tprivate static void PaintRow( VirtualWidget item )\n\t{\n\t\tif ( item.Object is not TreeNode node ) return;\n\t\titem.Selected = tree.IsSelected( item.Object );\n\t\tPaint.SetFlags( item.Selected, item.Hovered, item.Pressed, false, true );\n\t\tvar rect = item.Rect;\n\t\tvar childrenRect = item.ChildrenRect;\n\t\tvar oldIndent = item.Indent;\n\t\tvar indent = tree.IndentWidth * item.Column \u002B tree.ExpandWidth;\n\t\ttry\n\t\t{\n\t\t\titem.Indent = indent;\n\t\t\titem.Rect.Left \u002B= indent;\n\t\t\titem.ChildrenRect.Left \u002B= indent \u002B tree.IndentWidth;\n\t\t\t// Specialized prefab/scene root nodes keep their own painter.\n\t\t\tif ( node.GetType().Name == \u0022GameObjectNode\u0022 \u0026\u0026 node.Value is GameObject go\n\t\t\t\t\u0026\u0026 go.IsValid() \u0026\u0026 assignments.TryGetValue( Key( go ), out var style ) \u0026\u0026 (style \u0026 BoldFlag) != 0 )\n\t\t\t\tBoldHierarchyRow.PaintBold( item, go, tree );\n\t\t\telse node.OnPaint( item );\n\t\t}\n\t\tfinally\n\t\t{\n\t\t\t// Hit-testing shares these layouts; never leave paint indentation behind.\n\t\t\titem.Rect = rect;\n\t\t\titem.ChildrenRect = childrenRect;\n\t\t\titem.Indent = oldIndent;\n\t\t}\n\t\tif ( !item.HasChildren || node.ExpanderHidden ) return;\n\t\tvar expander = rect;\n\t\texpander.Left \u002B= indent - tree.ExpandWidth;\n\t\texpander.Width = tree.ExpandWidth;\n\t\tPaint.SetPen( Theme.Text.WithAlpha( item.IsOpen ? 1 : 0.6f ) );\n\t\tPaint.DrawIcon( expander, item.IsOpen ? \u0022arrow_drop_down\u0022 : \u0022arrow_right\u0022, 26, TextFlag.Center );\n\t}\n}\n"},{"Ident":"yugi.hierarchychanges","Path":"Editor/BoldHierarchyRow.cs","FileName":"BoldHierarchyRow.cs","PackageType":"library","CodeKind":"Editor","AssetVersionId":381874,"Code":"using Editor;\nusing Sandbox;\nusing System;\nusing System.Linq;\nusing static Editor.BaseItemWidget;\n\nnamespace HierarchyChanges;\n\n// Adapted from Facepunch\u0027s installed GameObjectNode.OnPaint (2026-09-06).\n// Source: sbox-public/game/addons/tools/Code/Scene/SceneTree/GameObjectNode.cs.\n// Keep this compatibility copy aligned with upstream hierarchy indicators.\n// Only the object name uses weight 700; following status text returns to normal.\ninternal static class BoldHierarchyRow\n{\n\tinternal static void PaintBold( VirtualWidget item, GameObject Value, TreeView TreeView )\n\t{\n\t\tif ( !Value.Scene.IsValid() )\n\t\t\treturn;\n\n\t\tvar isEven = item.Row % 2 == 0;\n\t\tvar isHovered = item.Hovered;\n\t\tvar selected = item.Selected || item.Pressed || item.Dragging;\n\t\tvar isBone = Value.Flags.Contains( GameObjectFlags.Bone );\n\t\tvar isProceduralBone = Value.Flags.Contains( GameObjectFlags.ProceduralBone );\n\t\tvar isAttachment = Value.Flags.Contains( GameObjectFlags.Attachment );\n\t\tvar isNetworked = Value.Scene.IsEditor ? Value.NetworkMode == NetworkMode.Object : Value.Network.Active;\n\t\tvar isNetworkRoot = isNetworked \u0026\u0026 (Value.Scene.IsEditor ? Value.NetworkMode == NetworkMode.Object : Value.IsNetworkRoot);\n\n\t\tbool isErrored = Value.Flags.Contains( GameObjectFlags.Error );\n\t\tbool isLoading = Value.Flags.Contains( GameObjectFlags.Loading );\n\t\tbool isTemporary = Value.Flags.Contains( GameObjectFlags.NotSaved );\n\t\tbool isEditorOnly = Value.Flags.Contains( GameObjectFlags.EditorOnly );\n\n\t\tvar fullSpanRect = item.Rect;\n\t\tfullSpanRect.Left = 0;\n\t\tfullSpanRect.Right = TreeView.Width;\n\n\t\tfloat opacity = 0.9f;\n\n\t\tif ( !Value.Active ) opacity *= 0.5f;\n\n\t\tColor pen = Theme.TextControl;\n\t\tstring icon = \u0022layers\u0022;\n\t\tColor iconColor = Theme.TextControl.WithAlpha( 0.6f );\n\t\tColor overlayIconColor = iconColor;\n\n\t\tstring overlayIcon = null;\n\n\t\tif ( Value.IsPrefabInstance )\n\t\t{\n\t\t\tpen = Theme.Blue;\n\t\t\toverlayIconColor = Theme.Blue;\n\n\t\t\tif ( Value.IsPrefabInstanceRoot )\n\t\t\t{\n\t\t\t\ticon = \u0022dataset\u0022;\n\t\t\t\ticonColor = Theme.Blue;\n\n\t\t\t\tif ( EditorUtility.Prefabs.IsInstanceModified( Value ) )\n\t\t\t\t{\n\t\t\t\t\tPaint.ClearPen();\n\t\t\t\t\tPaint.SetBrush( Theme.Blue.Darken( 0.25f ) );\n\t\t\t\t\tvar modifiedRect = fullSpanRect;\n\t\t\t\t\tmodifiedRect.Width = 2;\n\t\t\t\t\tPaint.DrawRect( modifiedRect );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( EditorUtility.Prefabs.IsGameObjectAddedToInstance( Value ) )\n\t\t\t{\n\t\t\t\toverlayIcon = \u0022add_circle\u0022;\n\t\t\t}\n\t\t}\n\n\t\tif ( isBone )\n\t\t{\n\t\t\ticon = \u0022polyline\u0022;\n\t\t\ticonColor = Theme.Pink.WithAlpha( 0.8f );\n\n\t\t\tif ( isProceduralBone )\n\t\t\t{\n\t\t\t\ticonColor = Theme.Blue.WithAlpha( 0.8f );\n\t\t\t}\n\t\t}\n\n\t\tif ( isAttachment )\n\t\t{\n\t\t\ticon = \u0022push_pin\u0022;\n\t\t\ticonColor = Theme.Pink.WithAlpha( 0.8f );\n\n\t\t\tif ( isProceduralBone )\n\t\t\t{\n\t\t\t\ticonColor = Theme.Blue.WithAlpha( 0.8f );\n\t\t\t}\n\t\t}\n\n\t\tif ( isTemporary )\n\t\t{\n\t\t\ticonColor = Color.White.WithAlpha( 0.5f );\n\t\t\tpen = iconColor.Lighten( 0.2f ).WithAlpha( 0.8f );\n\t\t\ticon = \u0022no_sim\u0022;\n\t\t}\n\n\t\tif ( isNetworked )\n\t\t{\n\t\t\ticon = \u0022rss_feed\u0022;\n\t\t\ticonColor = Theme.Blue.WithAlpha( 0.8f );\n\n\t\t\tif ( Value.Network.IsOwner )\n\t\t\t{\n\t\t\t\ticonColor = Theme.Green.WithAlpha( 0.8f );\n\t\t\t}\n\n\t\t\tif ( Value.IsProxy )\n\t\t\t{\n\t\t\t\ticonColor = Theme.TextControl.WithAlpha( 0.6f );\n\t\t\t}\n\n\t\t\tif ( !isNetworkRoot ) iconColor = iconColor.WithAlphaMultiplied( 0.4f );\n\t\t}\n\n\t\tif ( isErrored )\n\t\t{\n\t\t\ticon = \u0022report\u0022;\n\t\t\ticonColor = Theme.Red.WithAlpha( 0.8f );\n\t\t}\n\n\t\tif ( isEditorOnly )\n\t\t{\n\t\t\ticon = \u0022highlight_alt\u0022;\n\t\t\ticonColor = Theme.Yellow.WithAlpha( 0.8f );\n\t\t\tpen = Theme.Yellow.WithAlpha( 0.6f );\n\t\t}\n\n\n\t\t//\n\t\t// If there\u0027s a drag and drop happening, fade out nodes that aren\u0027t possible\n\t\t//\n\t\tif ( TreeView.IsBeingDroppedOn )\n\t\t{\n\t\t\tif ( TreeView.CurrentItemDragEvent.Data.Object is GameObject[] gos \u0026\u0026 gos.Any( go =\u003E Value.IsAncestor( go ) ) )\n\t\t\t{\n\t\t\t\topacity *= 0.23f;\n\t\t\t}\n\t\t\telse if ( TreeView.CurrentItemDragEvent.Data.Object is GameObject go \u0026\u0026 Value.IsAncestor( go ) )\n\t\t\t{\n\t\t\t\topacity *= 0.23f;\n\t\t\t}\n\t\t}\n\n\t\tif ( item.Dropping )\n\t\t{\n\t\t\tPaint.ClearPen();\n\t\t\tPaint.SetBrush( Theme.Blue );\n\n\t\t\tif ( TreeView.CurrentItemDragEvent.DropEdge.HasFlag( ItemEdge.Top ) )\n\t\t\t{\n\t\t\t\tvar droprect = item.Rect;\n\t\t\t\tdroprect.Top -= 1;\n\t\t\t\tdroprect.Height = 2;\n\t\t\t\tPaint.DrawRect( droprect, 2 );\n\t\t\t}\n\t\t\telse if ( TreeView.CurrentItemDragEvent.DropEdge.HasFlag( ItemEdge.Bottom ) )\n\t\t\t{\n\t\t\t\tvar droprect = item.Rect;\n\t\t\t\tdroprect.Top = droprect.Bottom - 1;\n\t\t\t\tdroprect.Height = 2;\n\t\t\t\tPaint.DrawRect( droprect, 2 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPaint.SetBrushAndPen( Theme.Blue.WithAlpha( 0.2f ), Theme.Blue );\n\t\t\t\tPaint.PenSize = 2;\n\t\t\t\tPaint.DrawRect( item.Rect, 4 );\n\t\t\t}\n\t\t}\n\n\t\tif ( selected )\n\t\t{\n\t\t\t//item.PaintBackground( Color.Transparent, 3 );\n\t\t\tPaint.ClearPen();\n\t\t\tPaint.SetBrush( Theme.SelectedBackground.WithAlpha( opacity ) );\n\t\t\tPaint.DrawRect( fullSpanRect );\n\t\t}\n\t\telse if ( isHovered )\n\t\t{\n\t\t\tPaint.ClearPen();\n\t\t\tPaint.SetBrush( Theme.SelectedBackground.WithAlpha( 0.25f ) );\n\t\t\tPaint.DrawRect( fullSpanRect );\n\t\t}\n\t\telse if ( isEven )\n\t\t{\n\t\t\tPaint.ClearPen();\n\t\t\tPaint.SetBrush( Theme.SurfaceLightBackground.WithAlpha( 0.1f ) );\n\t\t\tPaint.DrawRect( fullSpanRect );\n\t\t}\n\n\t\tvar name = Value.Name;\n\t\tif ( string.IsNullOrWhiteSpace( name ) ) name = \u0022Untitled GameObject\u0022;\n\n\t\tvar r = item.Rect;\n\t\tr.Left \u002B= 4;\n\n\t\tvar iconSize = 16;\n\n\t\tPaint.Pen = iconColor.WithAlphaMultiplied( opacity );\n\t\tPaint.DrawIcon( r, icon, iconSize, TextFlag.LeftCenter );\n\t\tif ( !string.IsNullOrEmpty( overlayIcon ) )\n\t\t{\n\t\t\tvar overlayIconRect = r;\n\t\t\toverlayIconRect.Left \u002B= 8;\n\t\t\toverlayIconRect.Top \u002B= 8;\n\t\t\toverlayIconRect.Width = 13;\n\t\t\toverlayIconRect.Height = 13;\n\t\t\tPaint.Pen = Theme.WidgetBackground;\n\t\t\tPaint.SetBrush( Theme.WidgetBackground );\n\t\t\tPaint.DrawRect( overlayIconRect, 12 );\n\t\t\toverlayIconRect.Left \u002B= 1;\n\t\t\tPaint.Pen = overlayIconColor;\n\t\t\tPaint.DrawIcon( overlayIconRect, overlayIcon, 13, TextFlag.Center );\n\t\t}\n\t\tr.Left \u002B= 22;\n\n\t\tPaint.Pen = pen.WithAlphaMultiplied( opacity );\n\t\tPaint.SetDefaultFont( weight: 700 );\n\t\tr.Left \u002B= Paint.DrawText( r, name, TextFlag.LeftCenter ).Width \u002B 4;\n\n\t\tPaint.SetDefaultFont();\n\n\t\tif ( isLoading )\n\t\t{\n\t\t\tPaint.Pen = Theme.Blue;\n\t\t\tPaint.DrawIcon( r, \u0022access_time_filled\u0022, iconSize, TextFlag.LeftCenter );\n\t\t\tr.Left \u002B= 22;\n\t\t}\n\n\t\tif ( isNetworkRoot \u0026\u0026 Value.Network.OwnerId != Guid.Empty )\n\t\t{\n\t\t\tvar connection = Connection.Find( Value.Network.OwnerId );\n\t\t\tif ( connection is null )\n\t\t\t{\n\t\t\t\tPaint.Pen = Theme.Blue;\n\t\t\t\tPaint.DrawText( r, $\u0022Unknown Owner - {Value.Network.OwnerId}\u0022, TextFlag.LeftCenter );\n\t\t\t\tr.Left \u002B= 22;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPaint.Pen = Theme.Blue;\n\t\t\t\tPaint.DrawText( r, $\u0022{connection.DisplayName}\u0022, TextFlag.LeftCenter );\n\t\t\t\tr.Left \u002B= 22;\n\t\t\t}\n\n\n\t\t}\n\n\t\tif ( Value.Tags.Has( \u0022hidden\u0022 ) )\n\t\t{\n\t\t\tvar eyeRect = item.Rect;\n\t\t\teyeRect.Right -= 4;\n\t\t\teyeRect.Left = eyeRect.Right - 18;\n\n\t\t\tPaint.Pen = Theme.TextControl;\n\t\t\tPaint.DrawIcon( eyeRect, \u0022visibility_off\u0022, 14, TextFlag.Center );\n\t\t}\n\t}\n\n}\n\n"}]}