152 lines
4.6 KiB
C#
152 lines
4.6 KiB
C#
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
|
|
namespace AcDream.App.UI.Layout;
|
|
|
|
/// <summary>
|
|
/// Dat property value kinds carried by a retail <c>StateDesc</c>. The enum mirrors
|
|
/// <c>BasePropertyType</c> without exposing DatReaderWriter types to the retained UI.
|
|
/// </summary>
|
|
public enum UiPropertyKind : byte
|
|
{
|
|
Enum,
|
|
Bool,
|
|
DataId,
|
|
Float,
|
|
Integer,
|
|
StringInfo,
|
|
Color,
|
|
Array,
|
|
Struct,
|
|
Vector,
|
|
Bitfield32,
|
|
Bitfield64,
|
|
InstanceId,
|
|
}
|
|
|
|
/// <summary>Exact byte representation of a retail ARGB property value.</summary>
|
|
public readonly record struct UiColorValue(byte Blue, byte Green, byte Red, byte Alpha);
|
|
|
|
/// <summary>Dat-independent snapshot of a retail <c>StringInfo</c>.</summary>
|
|
public readonly record struct UiStringInfoValue(
|
|
byte Token,
|
|
uint StringId,
|
|
uint TableId,
|
|
byte Override,
|
|
byte English,
|
|
byte Comment);
|
|
|
|
/// <summary>
|
|
/// Lossless, serializable representation of one supported retail base property.
|
|
/// Only the field selected by <see cref="Kind"/> is meaningful. Arrays and structs
|
|
/// recursively preserve their members and each member's master-property id.
|
|
/// </summary>
|
|
public sealed class UiPropertyValue
|
|
{
|
|
public UiPropertyKind Kind;
|
|
public uint MasterPropertyId;
|
|
public ulong UnsignedValue;
|
|
public int IntegerValue;
|
|
public float FloatValue;
|
|
public bool BoolValue;
|
|
public UiStringInfoValue StringInfoValue;
|
|
public UiColorValue ColorValue;
|
|
public Vector3 VectorValue;
|
|
public List<UiPropertyValue> ArrayValue = new();
|
|
public Dictionary<uint, UiPropertyValue> StructValue = new();
|
|
|
|
public UiPropertyValue Clone()
|
|
{
|
|
var clone = new UiPropertyValue
|
|
{
|
|
Kind = Kind,
|
|
MasterPropertyId = MasterPropertyId,
|
|
UnsignedValue = UnsignedValue,
|
|
IntegerValue = IntegerValue,
|
|
FloatValue = FloatValue,
|
|
BoolValue = BoolValue,
|
|
StringInfoValue = StringInfoValue,
|
|
ColorValue = ColorValue,
|
|
VectorValue = VectorValue,
|
|
};
|
|
|
|
foreach (var item in ArrayValue)
|
|
clone.ArrayValue.Add(item.Clone());
|
|
foreach (var (key, value) in StructValue)
|
|
clone.StructValue[key] = value.Clone();
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// State-scoped retail properties. Presence of a key is authoritative: an explicit
|
|
/// false, zero, centered justification, or empty collection still overrides a base
|
|
/// value during inheritance.
|
|
/// </summary>
|
|
public sealed class UiPropertyBag
|
|
{
|
|
public Dictionary<uint, UiPropertyValue> Values = new();
|
|
|
|
public bool TryGetValue(uint id, out UiPropertyValue value)
|
|
=> Values.TryGetValue(id, out value!);
|
|
|
|
public UiPropertyBag Clone()
|
|
{
|
|
var clone = new UiPropertyBag();
|
|
foreach (var (key, value) in Values)
|
|
clone.Values[key] = value.Clone();
|
|
return clone;
|
|
}
|
|
|
|
public static UiPropertyBag Merge(UiPropertyBag baseProperties, UiPropertyBag derivedProperties)
|
|
{
|
|
var merged = baseProperties.Clone();
|
|
foreach (var (key, value) in derivedProperties.Values)
|
|
merged.Values[key] = value.Clone();
|
|
return merged;
|
|
}
|
|
}
|
|
|
|
/// <summary>Primary render-surface media for a retail UI state.</summary>
|
|
public readonly record struct UiImageMedia(uint File, int DrawMode);
|
|
|
|
/// <summary>
|
|
/// Dat-independent state descriptor. DirectState uses
|
|
/// <see cref="DirectStateId"/> so it cannot collide with <c>UIStateId.Undef == 0</c>.
|
|
/// </summary>
|
|
public sealed class UiStateInfo
|
|
{
|
|
public const uint DirectStateId = uint.MaxValue;
|
|
|
|
public uint Id;
|
|
public string Name = "";
|
|
public bool PassToChildren;
|
|
public uint IncorporationFlags;
|
|
public UiImageMedia? Image;
|
|
public UiCursorMedia? Cursor;
|
|
public UiPropertyBag Properties = new();
|
|
|
|
public UiStateInfo Clone()
|
|
=> new()
|
|
{
|
|
Id = Id,
|
|
Name = Name,
|
|
PassToChildren = PassToChildren,
|
|
IncorporationFlags = IncorporationFlags,
|
|
Image = Image,
|
|
Cursor = Cursor,
|
|
Properties = Properties.Clone(),
|
|
};
|
|
|
|
public static UiStateInfo Merge(UiStateInfo baseState, UiStateInfo derivedState)
|
|
=> new()
|
|
{
|
|
Id = derivedState.Id,
|
|
Name = derivedState.Name,
|
|
PassToChildren = derivedState.PassToChildren,
|
|
IncorporationFlags = derivedState.IncorporationFlags,
|
|
Image = derivedState.Image ?? baseState.Image,
|
|
Cursor = derivedState.Cursor ?? baseState.Cursor,
|
|
Properties = UiPropertyBag.Merge(baseState.Properties, derivedState.Properties),
|
|
};
|
|
}
|