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,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.UI.Abstractions.Panels.Settings;
|
||||
|
||||
|
|
@ -130,6 +131,24 @@ namespace AcDream.App.UI.Layout;
|
|||
/// <c>0x004039ed</c>, NOT a per-machine runtime enumeration as the
|
||||
/// rejected slice's comment claimed).
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Caption dimming (AD-78, user-directed, 2026-08-11, gate 2).</b> Every
|
||||
/// STORE-ONLY row above (the 21 rows named in the paragraph before this one
|
||||
/// -- AP-198's ten, AP-199's three, and TS-74's six Camera/Input rows plus
|
||||
/// AP-200's two Chat-font rows) renders its caption in
|
||||
/// <see cref="UiRenderContext.StoreOnlyCaptionColor"/> instead of the normal
|
||||
/// white/DAT-authored color. The row stays fully interactive -- it still
|
||||
/// persists -- the dim is ONLY a visual marker so the four-tab panel makes
|
||||
/// "does this actually do anything yet" legible at a glance, per the
|
||||
/// campaign's gate-2 directive. LIVE rows (Sound/Ambient trios, Resolution,
|
||||
/// Full Screen) and NEXT-LAUNCH rows (Sync To Refresh, Field of View -- they
|
||||
/// DO apply, just not until the next process start) are NOT dimmed. Threaded
|
||||
/// through every row builder below as an explicit <c>storeOnly</c> parameter
|
||||
/// at each of the 27 call sites, so wiring a future consumer means flipping
|
||||
/// that literal to <see langword="false"/> -- the matching conformance test
|
||||
/// then fails until the change is made consciously.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class ConfigOptionsPageController
|
||||
{
|
||||
|
|
@ -317,7 +336,8 @@ public static class ConfigOptionsPageController
|
|||
AudioSettings updated = bindings.LoadAudio() with { SoundFeatures = value };
|
||||
bindings.SaveAudio(updated);
|
||||
},
|
||||
defaultValue: 0);
|
||||
defaultValue: 0,
|
||||
storeOnly: true); // AP-199
|
||||
|
||||
// OP6 rework (2026-08-11, review M2): read/apply the ENABLED-sense
|
||||
// fields directly — toggleDefault stays `true` because retail's own
|
||||
|
|
@ -339,7 +359,8 @@ public static class ConfigOptionsPageController
|
|||
toggleRead: () => bindings.LoadAudio().SfxEnabled,
|
||||
toggleApply: value => bindings.SaveAudio(bindings.LoadAudio() with { SfxEnabled = value }),
|
||||
sliderRead: () => bindings.LoadAudio().Sfx,
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { Sfx = value }));
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { Sfx = value }),
|
||||
storeOnly: false); // LIVE
|
||||
|
||||
BuildTrioRow(
|
||||
listBox, "ID_Sound_DisableAmbientSound", sliderTooltipKey: "ID_Sound_AmbientVolume",
|
||||
|
|
@ -349,7 +370,8 @@ public static class ConfigOptionsPageController
|
|||
toggleRead: () => bindings.LoadAudio().AmbientEnabled,
|
||||
toggleApply: value => bindings.SaveAudio(bindings.LoadAudio() with { AmbientEnabled = value }),
|
||||
sliderRead: () => bindings.LoadAudio().Ambient,
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { Ambient = value }));
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { Ambient = value }),
|
||||
storeOnly: false); // LIVE
|
||||
|
||||
// Interface Sound: retail's own dead knob (AP-174 — "interface
|
||||
// sounds are scaled by the EFFECT knob"; registered and never
|
||||
|
|
@ -363,12 +385,14 @@ public static class ConfigOptionsPageController
|
|||
toggleRead: () => bindings.LoadAudio().InterfaceEnabled,
|
||||
toggleApply: value => bindings.SaveAudio(bindings.LoadAudio() with { InterfaceEnabled = value }),
|
||||
sliderRead: () => bindings.LoadAudio().InterfaceVolume,
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { InterfaceVolume = value }));
|
||||
sliderApply: value => bindings.SaveAudio(bindings.LoadAudio() with { InterfaceVolume = value }),
|
||||
storeOnly: true); // AP-174 / AP-199
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Sound_NoFocusNoSound", defaultValue: true, page, resolveString,
|
||||
read: () => bindings.LoadAudio().PlaySoundOnlyWhenActive,
|
||||
apply: value => bindings.SaveAudio(bindings.LoadAudio() with { PlaySoundOnlyWhenActive = value }));
|
||||
apply: value => bindings.SaveAudio(bindings.LoadAudio() with { PlaySoundOnlyWhenActive = value }),
|
||||
storeOnly: true); // AP-199
|
||||
|
||||
audio = bindings.LoadAudio();
|
||||
}
|
||||
|
|
@ -393,6 +417,7 @@ public static class ConfigOptionsPageController
|
|||
min: 0.285714298f, max: 1f, defaultValue: 0.45f, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().Stiffness,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { Stiffness = value }),
|
||||
storeOnly: true, // TS-74
|
||||
rangeLowKey: "ID_Graphics_Value_Soft", rangeHighKey: "ID_Graphics_Value_Hard");
|
||||
|
||||
BuildSliderRow(
|
||||
|
|
@ -400,6 +425,7 @@ public static class ConfigOptionsPageController
|
|||
min: 5f, max: 80f, defaultValue: 40.0f, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().AdjustmentSpeed,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { AdjustmentSpeed = value }),
|
||||
storeOnly: true, // TS-74
|
||||
rangeLowKey: "ID_Graphics_Value_Slow", rangeHighKey: "ID_Graphics_Value_Fast");
|
||||
|
||||
// Field of View: NEXT-LAUNCH via DisplaySettings.FieldOfView + the
|
||||
|
|
@ -411,12 +437,14 @@ public static class ConfigOptionsPageController
|
|||
min: 10f, max: 160f, defaultValue: 90.0f, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().FieldOfView,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { FieldOfView = value }),
|
||||
storeOnly: false, // NEXT-LAUNCH, not store-only
|
||||
rangeLowKey: "ID_Graphics_Value_Narrow", rangeHighKey: "ID_Graphics_Value_Wide");
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Camera_AlignToSlope", defaultValue: true, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().AlignToSlope,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { AlignToSlope = value }));
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { AlignToSlope = value }),
|
||||
storeOnly: true); // TS-74
|
||||
|
||||
cameraTurning = bindings.LoadCameraTurning();
|
||||
}
|
||||
|
|
@ -455,19 +483,22 @@ public static class ConfigOptionsPageController
|
|||
DisplaySettings.AvailableResolutions, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().Resolution,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { Resolution = value }),
|
||||
defaultValue: "800x600");
|
||||
defaultValue: "800x600",
|
||||
storeOnly: false); // LIVE
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Rendering_FullScreen", defaultValue: true, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().Fullscreen,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { Fullscreen = value }));
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { Fullscreen = value }),
|
||||
storeOnly: false); // LIVE
|
||||
|
||||
// Sync To Refresh: NEXT-LAUNCH (same DisplaySettings.VSync
|
||||
// pre-existing precedent as FieldOfView above).
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Rendering_SyncToDisplayRefresh", defaultValue: false, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().VSync,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { VSync = value }));
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { VSync = value }),
|
||||
storeOnly: false); // NEXT-LAUNCH, not store-only
|
||||
|
||||
// Screen Brightness: OP6 rework (2026-08-11, review S2) — its OWN
|
||||
// DisplaySettings.ScreenBrightness field ([-1,1], default 0), NOT
|
||||
|
|
@ -479,18 +510,21 @@ public static class ConfigOptionsPageController
|
|||
min: -1f, max: 1f, defaultValue: 0f, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().ScreenBrightness,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { ScreenBrightness = value }),
|
||||
storeOnly: true, // review S2
|
||||
rangeLowKey: "ID_Graphics_Value_Dark", rangeHighKey: "ID_Graphics_Value_Bright");
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Graphics_AdaptiveDegrade", defaultValue: false, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().AutomaticDegrades,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { AutomaticDegrades = value }));
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { AutomaticDegrades = value }),
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
BuildSliderRow(
|
||||
listBox, RangedSliderTemplateIndex, "ID_Graphics_AdaptiveDegradeBias",
|
||||
min: -1f, max: 1f, defaultValue: 0f, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().GraphicsPerformance,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { GraphicsPerformance = value }),
|
||||
storeOnly: true, // AP-198
|
||||
rangeLowKey: "ID_Graphics_Value_Speed", rangeHighKey: "ID_Graphics_Value_Detail");
|
||||
|
||||
BuildSliderRow(
|
||||
|
|
@ -498,6 +532,7 @@ public static class ConfigOptionsPageController
|
|||
min: 0f, max: 100f, defaultValue: 50.0f, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().DegradeDistance,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { DegradeDistance = value }),
|
||||
storeOnly: true, // AP-198
|
||||
rangeLowKey: "ID_Graphics_Value_Close", rangeHighKey: "ID_Graphics_Value_Far");
|
||||
|
||||
display = bindings.LoadDisplay();
|
||||
|
|
@ -539,19 +574,22 @@ public static class ConfigOptionsPageController
|
|||
listBox, "ID_Graphics_LandscapeTextureDetail", TextureDetailChoices, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().LandscapeTextureDetail,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { LandscapeTextureDetail = value }),
|
||||
defaultValue: 2);
|
||||
defaultValue: 2,
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
BuildMenuRow(
|
||||
listBox, "ID_Graphics_EnvironmentTextureDetail", TextureDetailChoices, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().EnvironmentTextureDetail,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { EnvironmentTextureDetail = value }),
|
||||
defaultValue: 1);
|
||||
defaultValue: 1,
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
BuildMenuRow(
|
||||
listBox, "ID_Graphics_TextureFiltering", TextureFilteringChoices, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().TextureFiltering,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { TextureFiltering = value }),
|
||||
defaultValue: 1);
|
||||
defaultValue: 1,
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
// UNRESOLVED (see class doc / register row): retail's own
|
||||
// SetDefaultValue(8) does not index this 6-entry choice array.
|
||||
|
|
@ -561,17 +599,20 @@ public static class ConfigOptionsPageController
|
|||
listBox, "ID_Graphics_LandscapeDrawDistance", LandscapeDrawDistanceChoices, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().LandscapeDrawDistance,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { LandscapeDrawDistance = value }),
|
||||
defaultValue: 8);
|
||||
defaultValue: 8,
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Graphics_BuildingDetailTextures", defaultValue: true, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().BuildingDetailTextures,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { BuildingDetailTextures = value }));
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { BuildingDetailTextures = value }),
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Graphics_MultiPassAlpha", defaultValue: false, page, resolveString,
|
||||
read: () => bindings.LoadDisplay().MultiPassAlpha,
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { MultiPassAlpha = value }));
|
||||
apply: value => bindings.SaveDisplay(bindings.LoadDisplay() with { MultiPassAlpha = value }),
|
||||
storeOnly: true); // AP-198
|
||||
|
||||
display = bindings.LoadDisplay();
|
||||
}
|
||||
|
|
@ -595,12 +636,14 @@ public static class ConfigOptionsPageController
|
|||
listBox, SimpleSliderTemplateIndex, "ID_Input_MouseLookSensitivity",
|
||||
min: 0.00999999978f, max: 1f, defaultValue: 0.55f, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().MouseLookSensitivity,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { MouseLookSensitivity = value }));
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { MouseLookSensitivity = value }),
|
||||
storeOnly: true); // TS-74
|
||||
|
||||
BuildToggleRow(
|
||||
listBox, "ID_Input_InvertMouseLookYAxis", defaultValue: false, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().InvertMouseLookYAxis,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { InvertMouseLookYAxis = value }));
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { InvertMouseLookYAxis = value }),
|
||||
storeOnly: true); // TS-74
|
||||
|
||||
// Input_UseMouseTurning: the Config tab's OWN client-local
|
||||
// UIPreference — DISTINCT from the Gameplay tab macro's
|
||||
|
|
@ -609,7 +652,8 @@ public static class ConfigOptionsPageController
|
|||
BuildToggleRow(
|
||||
listBox, "ID_Input_UseMouseTurning", defaultValue: false, page, resolveString,
|
||||
read: () => bindings.LoadCameraTurning().UseMouseTurning,
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { UseMouseTurning = value }));
|
||||
apply: value => bindings.SaveCameraTurning(bindings.LoadCameraTurning() with { UseMouseTurning = value }),
|
||||
storeOnly: true); // TS-74
|
||||
|
||||
cameraTurning = bindings.LoadCameraTurning();
|
||||
}
|
||||
|
|
@ -662,13 +706,15 @@ public static class ConfigOptionsPageController
|
|||
listBox, "ID_UI_ChatFontFace", ChatFontFaceChoices, page, resolveString,
|
||||
read: () => bindings.LoadChat().ChatFontFace,
|
||||
apply: value => bindings.SaveChat(bindings.LoadChat() with { ChatFontFace = value }),
|
||||
defaultValue: 2);
|
||||
defaultValue: 2,
|
||||
storeOnly: true); // AP-200
|
||||
|
||||
BuildMenuRow(
|
||||
listBox, "ID_UI_ChatFontSize", ChatFontSizeChoices, page, resolveString,
|
||||
read: () => bindings.LoadChat().ChatFontSizeIndex,
|
||||
apply: value => bindings.SaveChat(bindings.LoadChat() with { ChatFontSizeIndex = value }),
|
||||
defaultValue: 1);
|
||||
defaultValue: 1,
|
||||
storeOnly: true); // AP-200
|
||||
|
||||
chat = bindings.LoadChat();
|
||||
}
|
||||
|
|
@ -712,7 +758,8 @@ public static class ConfigOptionsPageController
|
|||
OptionPage page,
|
||||
Func<uint, uint, string?> resolveString,
|
||||
Func<bool> read,
|
||||
Action<bool> apply)
|
||||
Action<bool> apply,
|
||||
bool storeOnly)
|
||||
{
|
||||
UiElement? row = listBox.AddItemFromTemplateList(ToggleTemplateIndex);
|
||||
if (row is null)
|
||||
|
|
@ -732,7 +779,7 @@ public static class ConfigOptionsPageController
|
|||
return;
|
||||
}
|
||||
|
||||
ApplyLabelAndTooltip(checkbox, labelKey, resolveString);
|
||||
ApplyLabelAndTooltip(checkbox, labelKey, resolveString, storeOnly);
|
||||
|
||||
bool initial = read();
|
||||
checkbox.Selected = initial;
|
||||
|
|
@ -774,6 +821,7 @@ public static class ConfigOptionsPageController
|
|||
Func<uint, uint, string?> resolveString,
|
||||
Func<float> read,
|
||||
Action<float> apply,
|
||||
bool storeOnly,
|
||||
string? rangeLowKey = null,
|
||||
string? rangeHighKey = null)
|
||||
{
|
||||
|
|
@ -787,7 +835,7 @@ public static class ConfigOptionsPageController
|
|||
}
|
||||
|
||||
if (UiElement.FindDescendant(row, SliderLabelElementId) is UiText label)
|
||||
SetLabelText(label, labelKey, resolveString);
|
||||
SetLabelText(label, labelKey, resolveString, storeOnly);
|
||||
|
||||
if (rangeLowKey is not null)
|
||||
SetRangeLabel(row, SliderRangeMinElementId, rangeLowKey, resolveString);
|
||||
|
|
@ -870,7 +918,8 @@ public static class ConfigOptionsPageController
|
|||
Func<bool> toggleRead,
|
||||
Action<bool> toggleApply,
|
||||
Func<float> sliderRead,
|
||||
Action<float> sliderApply)
|
||||
Action<float> sliderApply,
|
||||
bool storeOnly)
|
||||
{
|
||||
if (listBox.AddItemFromTemplateList(TrioTemplateIndex) is not UiOptionToggleSlider trio)
|
||||
{
|
||||
|
|
@ -891,7 +940,7 @@ public static class ConfigOptionsPageController
|
|||
return;
|
||||
}
|
||||
|
||||
ApplyLabelAndTooltip(checkbox, toggleLabelKey, resolveString);
|
||||
ApplyLabelAndTooltip(checkbox, toggleLabelKey, resolveString, storeOnly);
|
||||
|
||||
bool toggleInitial = toggleRead();
|
||||
checkbox.Selected = toggleInitial;
|
||||
|
|
@ -940,7 +989,8 @@ public static class ConfigOptionsPageController
|
|||
Func<uint, uint, string?> resolveString,
|
||||
Func<int> read,
|
||||
Action<int> apply,
|
||||
int defaultValue)
|
||||
int defaultValue,
|
||||
bool storeOnly)
|
||||
{
|
||||
UiElement? row = listBox.AddItemFromTemplateList(MenuTemplateIndex);
|
||||
if (row is null)
|
||||
|
|
@ -952,7 +1002,7 @@ public static class ConfigOptionsPageController
|
|||
}
|
||||
|
||||
if (UiElement.FindDescendant(row, MenuLabelElementId) is UiText label)
|
||||
SetLabelText(label, labelKey, resolveString);
|
||||
SetLabelText(label, labelKey, resolveString, storeOnly);
|
||||
|
||||
if (UiElement.FindDescendant(row, MenuElementId) is not UiMenu menu)
|
||||
{
|
||||
|
|
@ -1022,7 +1072,8 @@ public static class ConfigOptionsPageController
|
|||
Func<uint, uint, string?> resolveString,
|
||||
Func<string> read,
|
||||
Action<string> apply,
|
||||
string defaultValue)
|
||||
string defaultValue,
|
||||
bool storeOnly)
|
||||
{
|
||||
UiElement? row = listBox.AddItemFromTemplateList(MenuTemplateIndex);
|
||||
if (row is null)
|
||||
|
|
@ -1034,7 +1085,7 @@ public static class ConfigOptionsPageController
|
|||
}
|
||||
|
||||
if (UiElement.FindDescendant(row, MenuLabelElementId) is UiText label)
|
||||
SetLabelText(label, labelKey, resolveString);
|
||||
SetLabelText(label, labelKey, resolveString, storeOnly);
|
||||
|
||||
if (UiElement.FindDescendant(row, MenuElementId) is not UiMenu menu)
|
||||
{
|
||||
|
|
@ -1079,7 +1130,7 @@ public static class ConfigOptionsPageController
|
|||
}
|
||||
|
||||
private static void ApplyLabelAndTooltip(
|
||||
UiButton checkbox, string labelKey, Func<uint, uint, string?> resolveString)
|
||||
UiButton checkbox, string labelKey, Func<uint, uint, string?> resolveString, bool storeOnly)
|
||||
{
|
||||
string? label = resolveString(StringTableId, DatStringResolver.ComputeHash(labelKey));
|
||||
if (label is not null)
|
||||
|
|
@ -1089,6 +1140,13 @@ public static class ConfigOptionsPageController
|
|||
$"[D.2b] ConfigOptionsPageController: label '{labelKey}' did not resolve — "
|
||||
+ "row renders with no caption rather than invented English.");
|
||||
|
||||
// AD-78: store-only rows keep their full interactivity (see class
|
||||
// doc) — only the caption color changes, matching the existing
|
||||
// disabled/ghosted convention (UiRenderContext.StoreOnlyCaptionColor).
|
||||
checkbox.LabelColor = storeOnly
|
||||
? UiRenderContext.StoreOnlyCaptionColor
|
||||
: Vector4.One;
|
||||
|
||||
string? tooltip = ResolveTooltip(labelKey, resolveString);
|
||||
if (tooltip is not null)
|
||||
checkbox.TooltipText = tooltip;
|
||||
|
|
@ -1106,7 +1164,8 @@ public static class ConfigOptionsPageController
|
|||
private static string? ResolveTooltip(string labelKey, Func<uint, uint, string?> resolveString)
|
||||
=> resolveString(StringTableId, DatStringResolver.ComputeHash(labelKey + "_Help"));
|
||||
|
||||
private static void SetLabelText(UiText label, string labelKey, Func<uint, uint, string?> resolveString)
|
||||
private static void SetLabelText(
|
||||
UiText label, string labelKey, Func<uint, uint, string?> resolveString, bool storeOnly)
|
||||
{
|
||||
string? text = resolveString(StringTableId, DatStringResolver.ComputeHash(labelKey));
|
||||
if (text is null)
|
||||
|
|
@ -1116,7 +1175,10 @@ public static class ConfigOptionsPageController
|
|||
+ "row renders with no caption rather than invented English.");
|
||||
return;
|
||||
}
|
||||
label.LinesProvider = () => new[] { new UiText.Line(text, label.DefaultColor) };
|
||||
// AD-78: store-only rows dim their caption instead of the DAT-authored
|
||||
// (or default white) color — see class doc.
|
||||
Vector4 color = storeOnly ? UiRenderContext.StoreOnlyCaptionColor : label.DefaultColor;
|
||||
label.LinesProvider = () => new[] { new UiText.Line(text, color) };
|
||||
}
|
||||
|
||||
private static UiButton? FindCheckbox(UiElement root)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue