fix(chargen): Campaign CC gate round 1 closeout — Group 1: real color wheel wiring

Lands Batch G's two STOPPED items, making the real palette-color swatch
wheel visually live instead of inert:

- UiButton and UiDatElement gain a per-instance Tint property threaded
  into every existing DrawSprite call (defaults to Vector4.One, so every
  pre-existing button/element is byte-identical unless a caller sets a
  non-identity tint).
- CharacterCreationAppearancePage now sets Tint directly on each color
  swatch button and the GradCircle element, replacing the Batch G
  flat-fill ChargenSwatchColorTile overlay outright — an opaque
  rectangle drawn on top can never reproduce retail's actual
  SurfaceWindow::BlitAndColor(..., Blit_Multiply, color) multiply blend,
  only a genuine per-instance sprite tint can, so the overlay approach is
  deleted rather than layered under the new mechanism.
- CharacterCreationUiController and RetailUiRuntime grow pass-through
  properties (AppearancePalSetSource/AppearanceClothingTableSource/
  AppearancePaletteColorSource) mirroring the existing PreviewControl
  seam, so LivePresentationComposition can wire a DAT-backed
  ChargenAppearanceCatalog into the Appearance page (wiring itself lands
  with the Group 3 commit, since it shares a file with an unrelated F16
  fix).

Register: AP-216/AP-217 RETIRED (161 -> now further reduced in later
commits) — both rows' remaining gaps are closed, not merely narrowed.
CharacterCreationAppearancePageSwatchColorTests updated for the new
Tint-based assertions (two pre-existing assertions were carried over
incorrectly from the old overlay-visibility model and are corrected).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-16 15:33:19 +02:00
parent 1f6365d3e5
commit e1d7d09599
7 changed files with 193 additions and 192 deletions

View file

@ -179,6 +179,15 @@ public class UiDatElement : UiElement, IUiDatStateful
/// <summary>Label color (default white).</summary>
public Vector4 LabelColor { get; set; } = Vector4.One;
/// <summary>
/// Campaign CC gate round 1 closeout (Group 1, R2-5): per-instance
/// multiplicative sprite tint, threaded into both <see cref="UiRenderContext.DrawSprite"/>
/// calls this class makes (the runtime-image path and the ordinary
/// authored-media path) — same shape and same default-identity
/// no-op-for-existing-callers guarantee as <see cref="UiButton.Tint"/>.
/// </summary>
public Vector4 Tint { get; set; } = Vector4.One;
/// <summary>Retail LayoutDesc property <c>0x21</c> (two-pass glyph outline,
/// <c>UIElement_Text::SetOutline @0x0046a81c</c>). Seeded in the ctor from the
/// element's effective-default state, same as <see cref="UiText.Outline"/>
@ -271,7 +280,7 @@ public class UiDatElement : UiElement, IUiDatStateful
0f,
1f,
1f,
Vector4.One);
Tint);
}
DrawLabel(ctx);
return;
@ -290,7 +299,7 @@ public class UiDatElement : UiElement, IUiDatStateful
// doc). Overlay/Alphablend use the same blit (the sprite shader
// already alpha-blends). No Stretch mode exists in DrawModeType;
// whole-canvas stretching happens at UiRoot.FixedCanvasSize.
ctx.DrawSprite(tex, 0, 0, Width, Height, 0, 0, Width / tw, Height / th, Vector4.One);
ctx.DrawSprite(tex, 0, 0, Width, Height, 0, 0, Width / tw, Height / th, Tint);
}
}