feat(ui): mark store-only option rows dimmed (user-directed, gate 2)

User directive (gate 2, verbatim): "mark all options that are not
implemented now, so I can clearly see what is not implemented." Store-only
rows keep full interactivity (still persist/send) but render their caption
in a shared dimmed grey (UiRenderContext.StoreOnlyCaptionColor, matching
the existing UiMenu.TextColorGhosted convention) instead of white/DAT
color. No invented marker text anywhere -- the dim IS the marker.

Config tab (ConfigOptionsPageController, 21 of 27 rows dimmed):
  Sound Features menu, Interface Sound trio, Play Sound Only When Active
  (AP-199); Screen Brightness, Automatic Degrades, Graphics Performance,
  Degrade Distance, the four Rendering Quality menus, Building Detail
  Textures, Multi-Pass Alpha (AP-198); Camera Stiffness, Camera Adjustment
  Speed, Align To Slope, Mouse Look Sensitivity, Invert Mouselook Y Axis,
  Use Mouse Turning (TS-74); Chat Font Face/Size (AP-200). NOT dimmed:
  Sound/Ambient trios, Resolution, Full Screen (LIVE), VSync and Field of
  View (NEXT-LAUNCH -- still implemented, just deferred to next process
  start, per the controller's own doc).

Character tab (CharacterOptionsPageController, 35 of 50 rows dimmed):
  every Group A (wire+store only) and Group D (deferred) row, plus the
  Group B rows the OP4 gate script's own step 16 confirms are unbound
  (ShowTooltips, SideBySideVitals, SpellDuration, AdvancedCombatUI,
  StayInChatMode, DisableMostWeatherEffects, PersistentAtDay,
  FilterLanguage, MainPackPreferred). NOT dimmed (15 rows): the six
  ListenTo*Chat ids (TurbineChatMembershipGate), DisableDistanceFog/
  DisplayTimeStamps/ToggleRun (bound at GameWindow.cs), the Group-C
  re-point (ViewCombatTarget/VividTargetingIndicator/CoordinatesOnRadar/
  AutoTarget/AutoRepeatAttack), and DragItemOnPlayerOpensSecureTrade
  (TS-48). Cross-checked against actual shipped consumers via source grep,
  not just the research doc's Group table, since OP4 only wired a subset
  of the doc's aspirational Group B.

Configure Keyboard (KeyboardConfigController): a row whose
RetailActionIdentityTable lookup fails (MappedAction null -- AP-203's
Emote/CharacterSettings set) dims its synthesized caption; the key
buttons stay fully bindable/persisted/conflict-checked.

Chat tab (ChatOptionsPageController): audited, zero store-only rows --
every filter block and both opacity sliders already have a live consumer
(ChatWindowState / RetailWindowOpacityController).

Ambiguity flagged, not guessed: the character-options-map.md research doc
lists AcceptLootPermits in BOTH Group A and Group C; its only code site
(LiveSessionRuntimeFactory.cs, the /consent command) is a second setter
for the same server bit, not a behavioral reader, so it is classified
Group A / dimmed here.

Register: AD-78 documents the convention (retail dims nothing; this is a
deliberate acdream-only divergence that retires as consumers land).

New per-surface conformance tests pin the exact dimmed/live set against a
literal expected list, so wiring a future consumer without also flipping
its row's literal fails the build:
CharacterOptionsPageControllerTests.StoreOnlyRows_MatchTheDerivationTableExactly
+ Bind_AppliesDimmedCaptionColor_ForStoreOnlyRows_AndWhiteForLiveRows,
ConfigOptionsPageControllerTests.CaptionDimming_MatchesTheStoreOnlySetExactly,
KeyboardConfigControllerTests.UnmappedRows_DimTheirCaption_MappedRowsStayWhite.

Build green; full Release suite 13,086 passed / 4 skipped / 0 failed
(baseline 13,082/4/0 -- delta is exactly the four new tests above).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-11 15:52:20 +02:00
parent 8bd7e3b88d
commit 3441a71833
10 changed files with 563 additions and 93 deletions

View file

@ -209,6 +209,23 @@ public sealed class UiRenderContext
/// 9 elements in the whole DAT set — every other outlined element uses this).</summary>
public static readonly Vector4 DefaultOutlineColor = new(0f, 0f, 0f, 1f);
/// <summary>
/// AD-78 (user-directed, 2026-08-11, Campaign OP gate 2): the shared caption
/// color for Options-panel / Configure-Keyboard rows that are store-only —
/// they persist (and, where auto-save, send the wire bit) but drive nothing
/// observable in acdream yet. Retail dims nothing here (every retail row has
/// a live consumer by construction); this is a deliberate acdream-only
/// convention so a store-only row is visually distinguishable from a live
/// one without any invented marker text. Same neutral grey as the existing
/// disabled/ghosted convention (<see cref="UiMenu.TextColorGhosted"/>,
/// retail's disabled StateDesc grey) — reused rather than a new color so the
/// "this doesn't do anything yet" signal reads consistently across the whole
/// UI. See AD-78 for the full citation list; the row retires as consumers
/// land (each landing un-dims its own rows via the owning controller's
/// conformance test).
/// </summary>
public static readonly Vector4 StoreOnlyCaptionColor = new(0.5f, 0.5f, 0.5f, 1f);
/// <summary>
/// Draw a single line of text with a retail dat font (<see cref="UiDatFont"/>),
/// at <paramref name="x"/>,<paramref name="y"/> = the top-left of the