Editor/StepIdAutoFixWindow.cs
#nullable disable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Sandbox;
using Editor;
public class StepIdAutoFixWindow : DockWindow
{
private readonly List<StepIdFixPlan> _plans;
private readonly Action _afterApply;
private Vector2 _mousePos;
private Rect _applyRect;
private Rect _cancelRect;
private float _scroll;
private StepIdAutoFixWindow( List<StepIdFixPlan> plans, Action afterApply )
{
_plans = plans ?? new();
_afterApply = afterApply;
Title = "Auto-add step IDs";
Size = new Vector2( 760, 560 );
MinimumSize = new Vector2( 560, 360 );
MouseTracking = true;
}
public static void Show( List<StepIdFixPlan> plans, Action afterApply )
{
new StepIdAutoFixWindow( plans, afterApply ).Show();
}
protected override void OnPaint()
{
base.OnPaint();
var pad = 18f;
var w = Width - pad * 2;
var y = 18f;
Paint.SetDefaultFont( size: 14, weight: 800 );
Paint.SetPen( new Color( 1f, 0.75f, 0.28f ) );
Paint.DrawText( new Rect( pad, y, w, 24 ), "Some endpoint steps are missing IDs.", TextFlag.LeftCenter );
y += 30;
Paint.SetDefaultFont( size: 9 );
Paint.SetPen( Color.White.WithAlpha( 0.7f ) );
Paint.DrawText( new Rect( pad, y, w, 18 ), "Preview the deterministic IDs below. Applying writes the updated .endpoint.yml and creates a .bak backup first.", TextFlag.LeftCenter );
y += 28;
var contentTop = y;
var drawY = contentTop - _scroll;
foreach ( var plan in _plans )
{
var added = ExtractAddedIdLines( plan ).ToList();
var h = 44 + Math.Max( 1, added.Count ) * 16;
if ( drawY + h > contentTop && drawY < Height - 70 )
{
Paint.SetBrush( Color.White.WithAlpha( 0.04f ) );
Paint.SetPen( Color.White.WithAlpha( 0.10f ) );
Paint.DrawRect( new Rect( pad, drawY, w, h ), 6 );
Paint.SetDefaultFont( size: 10, weight: 700 );
Paint.SetPen( Color.White.WithAlpha( 0.9f ) );
Paint.DrawText( new Rect( pad + 10, drawY + 8, w - 20, 16 ), Path.GetFileName( plan.FilePath ), TextFlag.LeftCenter );
var lineY = drawY + 28;
Paint.SetDefaultFont( size: 9 );
Paint.SetPen( new Color( 0.55f, 1f, 0.65f, 0.86f ) );
foreach ( var line in added )
{
Paint.DrawText( new Rect( pad + 18, lineY, w - 36, 15 ), $"+ {line.Trim()}", TextFlag.LeftCenter );
lineY += 16;
}
}
drawY += h + 10;
}
var totalHeight = drawY + _scroll - contentTop;
var maxScroll = Math.Max( 0, totalHeight - (Height - contentTop - 78) );
_scroll = Math.Clamp( _scroll, 0, maxScroll );
var btnY = Height - 48;
_cancelRect = new Rect( pad, btnY, 120, 32 );
_applyRect = new Rect( Width - pad - 180, btnY, 180, 32 );
DrawButton( _cancelRect, "Cancel", Color.White );
DrawButton( _applyRect, "Auto-add step IDs", Color.Green );
}
private static IEnumerable<string> ExtractAddedIdLines( StepIdFixPlan plan )
{
var oldLines = new HashSet<string>( (plan.OriginalText ?? "").Replace( "\r\n", "\n" ).Split( '\n' ).Select( x => x.Trim() ) );
foreach ( var line in (plan.UpdatedText ?? "").Replace( "\r\n", "\n" ).Split( '\n' ) )
{
var trimmed = line.Trim();
if ( trimmed.StartsWith( "id:" ) && !oldLines.Contains( trimmed ) ) yield return line;
else if ( trimmed.StartsWith( "- id:" ) && !oldLines.Contains( trimmed ) ) yield return line;
}
}
private void DrawButton( Rect rect, string label, Color color )
{
var hovered = rect.IsInside( _mousePos );
Paint.SetBrush( color.WithAlpha( hovered ? 0.18f : 0.08f ) );
Paint.SetPen( color.WithAlpha( hovered ? 0.55f : 0.25f ) );
Paint.DrawRect( rect, 5 );
Paint.SetDefaultFont( size: 10, weight: 800 );
Paint.SetPen( color.WithAlpha( hovered ? 1f : 0.8f ) );
Paint.DrawText( rect, label, TextFlag.Center );
}
protected override void OnMousePress( MouseEvent e )
{
base.OnMousePress( e );
if ( _cancelRect.IsInside( e.LocalPosition ) ) Close();
if ( _applyRect.IsInside( e.LocalPosition ) )
{
foreach ( var plan in _plans ) StepIdAutoFixer.ApplyPlanWithBackup( plan );
Close();
_afterApply?.Invoke();
}
}
protected override void OnMouseMove( MouseEvent e ) { _mousePos = e.LocalPosition; Update(); }
protected override void OnMouseWheel( WheelEvent e ) { _scroll = Math.Max( 0, _scroll + (e.Delta > 0 ? -48 : 48) ); Update(); e.Accept(); }
}