Editor/CodeDialog/CodeDialog.cs
using Editor;
using Grains.RazorDesigner.Wiring;
using Sandbox;
namespace Grains.RazorDesigner.CodeDialog;
public sealed class CodeDialog
{
private const string LogPrefix = "[Grains.RazorDesigner]";
internal const int DeleteButtonWidth = 28;
internal const int AddButtonMinWidth = 120;
private const int DialogButtonMinWidth = 80;
private readonly Widget _parent;
private readonly CodeDialogEditBuffer _buffer;
private Editor.Dialog _dialog;
public CodeDialog( Widget parent, WiringEnvelope current )
{
_parent = parent;
_buffer = new CodeDialogEditBuffer( current );
}
public void Show( System.Action<WiringEnvelope> onConfirm, System.Action onCancel = null )
{
_dialog = new Editor.Dialog( _parent );
_dialog.Window.WindowTitle = "Code — State & Parameters";
_dialog.Window.SetWindowIcon( "code" );
_dialog.Window.SetModal( true, true );
_dialog.Window.MinimumWidth = 720;
_dialog.Window.MinimumHeight = 520;
_dialog.Layout = Layout.Column();
_dialog.Layout.Margin = 0;
_dialog.Layout.Spacing = 0;
// Header strip — single-line hint above the splitter.
var hint = new Editor.Label( _dialog )
{
Text = "Declare State (private fields) and Parameters (public [Parameter] properties). "
+ "Methods, Lifecycle, and the Action editor land in W3.",
};
hint.SetStyles( "color: #888; font-size: 11px; padding: 8px 12px;" );
_dialog.Layout.Add( hint );
var splitter = new Splitter( _dialog ) { IsVertical = true };
splitter.SetStyles(
"QSplitter::handle { background-color: #1d1d1d; }" +
"QSplitter::handle:hover { background-color: #4aa0ff; }" );
splitter.HandleWidth = 4;
var stateTabWrap = new Widget( _dialog );
stateTabWrap.Layout = Layout.Column();
var stateHeader = new Editor.Label( _dialog ) { Text = "State" };
stateHeader.SetStyles( "font-weight: bold; padding: 6px 12px 0 12px;" );
stateTabWrap.Layout.Add( stateHeader );
var stateScroll = new ScrollArea( _dialog );
stateScroll.Canvas = new StateTab( _dialog, _buffer );
stateTabWrap.Layout.Add( stateScroll, 1 );
splitter.AddWidget( stateTabWrap );
var paramTabWrap = new Widget( _dialog );
paramTabWrap.Layout = Layout.Column();
var paramHeader = new Editor.Label( _dialog ) { Text = "Parameters" };
paramHeader.SetStyles( "font-weight: bold; padding: 6px 12px 0 12px;" );
paramTabWrap.Layout.Add( paramHeader );
var paramScroll = new ScrollArea( _dialog );
paramScroll.Canvas = new ParameterTab( _dialog, _buffer );
paramTabWrap.Layout.Add( paramScroll, 1 );
splitter.AddWidget( paramTabWrap );
splitter.SetStretch( 0, 1 );
splitter.SetStretch( 1, 1 );
_dialog.Layout.Add( splitter, 1 );
var buttonRow = _dialog.Layout.Add( Layout.Row() );
buttonRow.Margin = 12;
buttonRow.Spacing = 6;
buttonRow.AddStretchCell();
var cancel = new Editor.Button( _dialog ) { Text = "Cancel", MinimumWidth = DialogButtonMinWidth };
cancel.MouseLeftPress += () =>
{
Log.Info( $"{LogPrefix} CodeDialog cancelled" );
_dialog.Close();
onCancel?.Invoke();
};
buttonRow.Add( cancel );
var ok = new Editor.Button( _dialog ) { Text = "Apply", MinimumWidth = DialogButtonMinWidth };
ok.MouseLeftPress += () =>
{
var env = _buffer.ToEnvelope();
Log.Info( $"{LogPrefix} CodeDialog applied: states={_buffer.States.Count}, parameters={_buffer.Parameters.Count}" );
_dialog.Close();
onConfirm?.Invoke( env );
};
buttonRow.Add( ok );
_dialog.Window.AdjustSize();
_dialog.Show();
}
}