Editor/CodeDialog/StateTab.cs
using System.Collections.Generic;
using Editor;
using Grains.RazorDesigner.Wiring;
using Sandbox;
namespace Grains.RazorDesigner.CodeDialog;
public sealed class StateTab : Widget
{
private const string LogPrefix = "[Grains.RazorDesigner]";
private readonly CodeDialogEditBuffer _buffer;
private readonly Layout _rowList;
public StateTab( Widget parent, CodeDialogEditBuffer buffer ) : base( parent )
{
_buffer = buffer;
Layout = Layout.Column();
Layout.Margin = 8;
Layout.Spacing = 4;
// Column header — fixed labels aligned with the row's stretch cells (2/1/1/2 + delete column).
var header = Layout.Row();
header.Spacing = 4;
header.Add( new Editor.Label( this ) { Text = "Name" }, 2 );
header.Add( new Editor.Label( this ) { Text = "Type" }, 1 );
header.Add( new Editor.Label( this ) { Text = "Visibility" }, 1 );
header.Add( new Editor.Label( this ) { Text = "Initial" }, 2 );
header.Add( new Widget( this ) { FixedWidth = CodeDialog.DeleteButtonWidth } ); // spacer for the × button column
Layout.Add( header );
_rowList = Layout.Column();
_rowList.Spacing = 2;
Layout.Add( _rowList );
Layout.AddStretchCell();
var addButton = new Editor.Button( this )
{
Text = "+ Add State",
Icon = "add",
MinimumWidth = CodeDialog.AddButtonMinWidth,
};
addButton.MouseLeftPress += OnAddClicked;
Layout.Add( addButton );
// Seed rows from the buffer.
foreach ( var s in _buffer.States ) AddRow( s );
Log.Info( $"{LogPrefix} StateTab ctor: seeded {_buffer.States.Count} row(s)" );
}
private void OnAddClicked()
{
var fresh = new StateSymbol
{
Name = MintFreshName(),
Type = "int",
Initial = InitialValueParser.Parse( "int", "0" ),
Visibility = SymbolVisibility.Private,
};
_buffer.States.Add( fresh );
AddRow( fresh );
Log.Info( $"{LogPrefix} StateTab.OnAddClicked: added '{fresh.Name}'; total={_buffer.States.Count}" );
}
private void AddRow( StateSymbol symbol )
{
var row = new StateSymbolRow( this, symbol );
row.Changed += () =>
{
// Locate by Id (stable across `with`-updates) and replace in place.
var idx = _buffer.States.FindIndex( s => s.Id == row.Symbol.Id );
if ( idx >= 0 ) _buffer.States[idx] = row.Symbol;
};
row.DeleteRequested += () =>
{
_buffer.States.RemoveAll( s => s.Id == row.Symbol.Id );
row.Destroy();
Log.Info( $"{LogPrefix} StateTab row deleted; total={_buffer.States.Count}" );
};
_rowList.Add( row );
}
private string MintFreshName()
{
var existing = new HashSet<string>();
foreach ( var s in _buffer.States ) existing.Add( s.Name ?? "" );
if ( !existing.Contains( "Count" ) ) return "Count";
for ( int i = 2; i < 1000; i++ )
{
var candidate = $"Count{i}";
if ( !existing.Contains( candidate ) ) return candidate;
}
return "Count";
}
}