Runtime/SuiElementProps.cs
using System.Collections.Generic;

namespace SboxUiDesigner.Runtime;

/// <summary>
/// Per-element type-specific properties. The generator picks the relevant subset
/// based on <see cref="SuiElement.Type"/>.
///
/// Implementation note: this class is a flat bag rather than a class hierarchy so
/// that Sandbox's GameResource serializer round-trips cleanly without polymorphic
/// type discriminators. The generator and validator only read fields relevant to
/// the element's type.
/// </summary>
public sealed class SuiElementProps
{
	// ---------- Text ----------

	public string Text { get; set; } = "";
	public float FontSize { get; set; } = 16f;
	public string FontFamily { get; set; }
	public SuiFontWeight FontWeight { get; set; } = SuiFontWeight.Normal;

	/// <summary>Hex color string, e.g. "#ffffff". Null = inherit.</summary>
	public string Color { get; set; } = "#ffffff";

	public SuiTextAlign TextAlign { get; set; } = SuiTextAlign.Left;
	public float? LineHeight { get; set; }
	public float LetterSpacing { get; set; } = 0f;
	public SuiTextOverflow TextOverflow { get; set; } = SuiTextOverflow.Clip;

	/// <summary>How the Text element sizes itself (Auto / Fixed / AutoHeightWrap).</summary>
	public SuiTextSizeMode TextSizeMode { get; set; } = SuiTextSizeMode.Auto;

	/// <summary>Only used when <see cref="TextSizeMode"/> is <see cref="SuiTextSizeMode.Fixed"/>.</summary>
	public SuiVerticalAlign VerticalAlign { get; set; } = SuiVerticalAlign.Top;

	// ---------- Image ----------

	public string ImagePath { get; set; }

	/// <summary>Hex color tint multiplied into the image. "#ffffff" = no tint.</summary>
	public string Tint { get; set; } = "#ffffff";

	public SuiImageFitMode FitMode { get; set; } = SuiImageFitMode.Contain;
	public SuiBackgroundPosition BackgroundPosition { get; set; } = SuiBackgroundPosition.Center;

	// ---------- Grid / InventoryGrid / Hotbar ----------

	public int Columns { get; set; } = 1;
	public int Rows { get; set; } = 1;
	public float CellWidth { get; set; } = 64f;
	public float CellHeight { get; set; } = 64f;
	public float GridGap { get; set; } = 4f;
	public bool AutoFill { get; set; } = false;
	public SuiGridGenerationStrategy GridStrategy { get; set; } = SuiGridGenerationStrategy.WrappedFlex;

	// ---------- Button ----------

	public string ButtonText { get; set; } = "";

	// ---------- ProgressBar ----------

	public float ProgressMin { get; set; } = 0f;
	public float ProgressMax { get; set; } = 100f;
	public float ProgressPreviewValue { get; set; } = 50f;
	public string ProgressFillColor { get; set; } = "#4ade80";
	public SuiProgressDirection ProgressDirection { get; set; } = SuiProgressDirection.LeftToRight;

	// ---------- Text wrap (Auto Wrap) ----------

	/// <summary>When true, Text wraps automatically. Same effect as TextSizeMode.AutoHeightWrap.</summary>
	public bool AutoWrapText { get; set; } = false;

	/// <summary>Pixel width to wrap at when AutoWrapText is true. 0 = use the element's Width.</summary>
	public float WrapTextAt { get; set; } = 0f;

	// ---------- Inventory slot / item ----------

	public int SlotIndex { get; set; } = 0;
	public string PreviewIconPath { get; set; }
	public int PreviewCount { get; set; } = 0;

	public SuiElementProps Clone() => new()
	{
		Text = Text,
		FontSize = FontSize,
		FontFamily = FontFamily,
		FontWeight = FontWeight,
		Color = Color,
		TextAlign = TextAlign,
		LineHeight = LineHeight,
		LetterSpacing = LetterSpacing,
		TextOverflow = TextOverflow,
		TextSizeMode = TextSizeMode,
		VerticalAlign = VerticalAlign,
		ImagePath = ImagePath,
		Tint = Tint,
		FitMode = FitMode,
		BackgroundPosition = BackgroundPosition,
		Columns = Columns,
		Rows = Rows,
		CellWidth = CellWidth,
		CellHeight = CellHeight,
		GridGap = GridGap,
		AutoFill = AutoFill,
		GridStrategy = GridStrategy,
		ButtonText = ButtonText,
		ProgressMin = ProgressMin,
		ProgressMax = ProgressMax,
		ProgressPreviewValue = ProgressPreviewValue,
		ProgressFillColor = ProgressFillColor,
		ProgressDirection = ProgressDirection,
		AutoWrapText = AutoWrapText,
		WrapTextAt = WrapTextAt,
		SlotIndex = SlotIndex,
		PreviewIconPath = PreviewIconPath,
		PreviewCount = PreviewCount,
	};
}

/// <summary>
/// Designer-only flags attached to every element. Not generated to runtime SCSS.
/// </summary>
public sealed class SuiElementFlags
{
	/// <summary>V1.5 — expose this element to the generated C# class as a [Property].</summary>
	public bool IsVariable { get; set; } = false;

	/// <summary>Locked elements cannot be moved/edited in the canvas (still selectable).</summary>
	public bool Locked { get; set; } = false;

	/// <summary>Hidden in the designer canvas/preview (still in document).</summary>
	public bool HiddenInDesigner { get; set; } = false;

	public SuiElementFlags Clone() => new()
	{
		IsVariable = IsVariable,
		Locked = Locked,
		HiddenInDesigner = HiddenInDesigner,
	};
}