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:
parent
8bd7e3b88d
commit
3441a71833
10 changed files with 563 additions and 93 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.Core.Input;
|
||||
using AcDream.UI.Abstractions.Input;
|
||||
|
|
@ -120,6 +121,18 @@ namespace AcDream.App.UI.Layout;
|
|||
/// retail's <c>OpenOverwriteBindingDialog(&conflicts)</c> — BEFORE reassigning;
|
||||
/// only on accept are the losing rows' slots erased and the new chord applied.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Caption dimming (AD-78, user-directed, 2026-08-11, gate 2).</b> A row
|
||||
/// whose <see cref="RowView.MappedAction"/> is null (AP-203's store-only
|
||||
/// set — mostly Emotes and CharacterSettings, plus every non-user-bindable
|
||||
/// InputMap this screen renders) dims its synthesized caption via
|
||||
/// <see cref="UiRenderContext.StoreOnlyCaptionColor"/> in
|
||||
/// <see cref="BuildActionRow"/>. The row stays fully rendered, bindable,
|
||||
/// conflict-checked, and persisted (per the paragraph above) — only the
|
||||
/// caption color changes, so the dim is a visual "no live gameplay consumer
|
||||
/// yet" marker, not a functional restriction.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class KeyboardConfigController
|
||||
{
|
||||
|
|
@ -332,9 +345,16 @@ public sealed class KeyboardConfigController
|
|||
string? label = resolveString(RetailInputMapHeaders.StringTableId, row.LabelHash);
|
||||
string? tooltip = resolveString(RetailInputMapHeaders.StringTableId, row.TooltipHash);
|
||||
|
||||
bool mapped = RetailActionIdentityTable.TryResolve(row.InputMapId, row.ActionId, out InputAction action);
|
||||
InputAction? mappedAction = mapped ? action : null;
|
||||
|
||||
// The row's own caption — synthesized, composed beside the authored key
|
||||
// buttons (UiText is sealed; see class doc). Occupies the "Command" column
|
||||
// (x=0..270, matching the authored column headers).
|
||||
// (x=0..270, matching the authored column headers). AD-78 (user-directed,
|
||||
// 2026-08-11, gate 2): an unmapped row (MappedAction null — no live
|
||||
// InputDispatcher consumer, AP-203) dims its caption; the key buttons
|
||||
// themselves stay fully interactive (bindable/persisted/conflict-checked,
|
||||
// see class doc).
|
||||
var captionText = new UiText
|
||||
{
|
||||
Left = 0f,
|
||||
|
|
@ -346,14 +366,12 @@ public sealed class KeyboardConfigController
|
|||
RightAligned = false,
|
||||
Padding = 2f,
|
||||
Anchors = AnchorEdges.Left | AnchorEdges.Top,
|
||||
DefaultColor = mapped ? Vector4.One : UiRenderContext.StoreOnlyCaptionColor,
|
||||
};
|
||||
if (label is not null)
|
||||
captionText.LinesProvider = () => new[] { new UiText.Line(label, captionText.DefaultColor) };
|
||||
built.AddChild(captionText);
|
||||
|
||||
bool mapped = RetailActionIdentityTable.TryResolve(row.InputMapId, row.ActionId, out InputAction action);
|
||||
InputAction? mappedAction = mapped ? action : null;
|
||||
|
||||
// M1: capture this row's live Activation/Scope ONCE, from the first
|
||||
// existing binding for the action (every multi-chord action in
|
||||
// KeyBindings.RetailDefaults() shares one Activation/Scope pair across
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue