Editor/UI/ArchExportDialog.cs
using System.Globalization;

namespace Sunless.Architecture;

// The one question an export cannot answer for itself. A Source unit is an inch, so a run written straight out
// lands twenty-four METRES wide in anything scaled to metres - and the author is the only one who knows which
// package it is going into. The answer is remembered, so it is asked once and confirmed thereafter.
public sealed class ArchExportDialog : Dialog {
	readonly Action<ArchExportSettings> export;
	readonly string subject;
	readonly Widget body;

	ArchExportSettings settings = ArchExportSettings.Remembered();

	public ArchExportDialog( Widget parent, string subject, Action<ArchExportSettings> export ) : base( parent ) {
		this.export = export;
		this.subject = subject;

		Window.Title = $"Export {subject}";
		Window.SetWindowIcon( "download" );
		Window.SetModal( true, true );
		Window.Size = new Vector2( 380, 340 );

		Layout = Layout.Column();
		Layout.Margin = 12;
		Layout.Spacing = 8;

		// The picks rebuild the body, and a control cannot clear the layout it is being clicked in - so the part
		// that changes lives one widget down and the footer never moves.
		body = new Widget( this ) { Layout = Layout.Column() };
		body.Layout.Spacing = 6;

		Layout.Add( body, 1 );

		var footer = Layout.AddRow();
		footer.Spacing = 4;
		footer.AddStretchCell();
		footer.Add( new Button( "Cancel", "close" ) { Clicked = Close } );
		footer.Add( new Button.Primary( "Export", "download" ) { Clicked = Keep } );

		Build();
	}

	void Build() {
		body.Layout.Clear( true );

		body.Layout.Add( ArchPartUi.Wrapped( $"Writing {subject} to Assets/{ArchExport.Directory}. Everything the "
			+ "preview stages is written, one object per generated piece." ) );

		body.Layout.Add( Heading( "Units" ) );

		using ( var grid = ArchIconGrid.In( body.Layout ) ) {
			Unit( grid, ArchExportUnits.SourceUnits, "Source units — inches, as the plan holds it, needing no import scale", "grid_4x4" );
			Unit( grid, ArchExportUnits.Metres, "Metres — a 600mm module comes in at 0.6", "straighten" );
			Unit( grid, ArchExportUnits.Centimetres, "Centimetres — a 600mm module comes in at 60", "square_foot" );
		}

		body.Layout.Add( Heading( "Up axis" ) );

		using ( var grid = ArchIconGrid.In( body.Layout ) ) {
			Up( grid, true, "Y up — what most OBJ importers expect", "swap_vert" );
			Up( grid, false, "Z up — Source's own, for an importer told to keep it", "vertical_align_top" );
		}

		body.Layout.Add( ArchPartUi.Wrapped( Reads() ) );
		body.Layout.AddStretchCell();
	}

	// Stated as a real-world length rather than as a factor, because the mistake this dialog exists to stop is a
	// scale one and a number with a unit on it is the only form of it anybody checks.
	string Reads() {
		var metre = ArchExportSettings.UnitsPerMetre * settings.Scale;

		return $"One metre writes out as {metre.ToString( "0.###", CultureInfo.InvariantCulture )} "
			+ $"{ArchExportSettings.Named( settings.Units )}.";
	}

	void Unit( ArchIconGrid grid, ArchExportUnits units, string tooltip, string glyph ) {
		grid.Pick( tooltip, $"arch_export_{units}".ToLowerInvariant(), glyph, settings.Units == units, () => {
			settings = settings with { Units = units };

			Build();
		} );
	}

	void Up( ArchIconGrid grid, bool y, string tooltip, string glyph ) {
		grid.Pick( tooltip, $"arch_export_up_{(y ? "y" : "z")}", glyph, settings.YUp == y, () => {
			settings = settings with { YUp = y };

			Build();
		} );
	}

	static Widget Heading( string text ) {
		var label = new Label( text );

		label.SetStyles( "font-size: 13px; font-weight: 700; margin-top: 8px;" );

		return label;
	}

	void Keep() {
		settings.Remember();
		export?.Invoke( settings );
		Close();
	}
}