feat(ui): Campaign OP slice OP5 — the Chat tab
Binds LayoutDesc 0x2100005C through OP2's template-list mechanism and OP3's per-page OptionPage model: the General Options header + two DualHash-linked opacity sliders (Option_DefaultOpacity_Property 0x10000080 / Option_ActiveOpacity_Property 0x10000081, live-apply on drag through RetailWindowOpacityController, defaults read from the installed DAT's DBProperties collection at DID 0x78000001 via ChatOptionsDatDefaults), and the five per-window text-filter blocks (main window 12 rows minus Gameplay, four floaties 13 rows each — the byte-verified authored order cross-checked against the raw gmChatOptionsUI::InitOptions/AddCheckboxBitfield64Option pseudo-C, not just the research doc's own table) writing AcDream.Core.Chat. ChatWindowState directly, the same state CH6's chat windows already read. AP-195 retired: ported both halves left open at the OP2 re-review — the ALL-set LED media swap (new UiButton.FaceFileOverride, driven by the block-level P0x10000082/P0x10000083 sprites now threaded through ElementInfo/DatWidgetFactory) and the CreateChildren self-sizing tail (UiCheckboxBitfield64.Height grows with its stacked row content; the enclosing ListBox reflows around the block's FINAL height via the new UiTemplateListBox.AddPrebuiltRow, reusing the ListBox's own stacking rather than a third stacking path). AP-187 broadened to cover the main window's own filter (previously only the four floaties) and the new live-editing write path. The main chat window's filter (retail window id 8, ChatWindowState id 0) gains its own settings.json persistence (ChatSettings. ChatWindowMainFilter) alongside the pre-existing floaty 1-4 fields; opacity persistence is now wired on every live slider change, not only through the old dev-scaffold Settings panel. Fixture regeneration (ACDREAM_REGENERATE_UI_FIXTURES=1) picked up the new ElementInfo.LedCheckedSprite/LedUncheckedSprite fields across all 19 committed layout fixtures — purely additive, confirmed against the live installed DAT (0x10000520's own 0x82/0x83 properties resolve to 0x06004D17/0x06004D19 exactly as AP-195 documented). Conformance: FilterRows/FilterBlocks pinned against the byte-verified authored order and ChatWindowState's own default constants; the AP-195 LED swap and self-sizing behavior; the DAT opacity-default extraction against the live installed DAT; live filter/opacity writes reaching ChatWindowState/RetailWindowOpacityController; OnShown re-seed and Reset/Defaults ghosting per the OP4 binding-pattern discipline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
4798302226
commit
e71e5a9614
52 changed files with 4540 additions and 40 deletions
|
|
@ -168,6 +168,198 @@ public sealed class BoolOptionRow : IOptionRow
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign OP slice OP5: the Chat tab's two linked opacity sliders' leaf —
|
||||
/// <c>UIOption_Slider</c>'s current/saved/default triple over a <see cref="float"/>,
|
||||
/// same shape as <see cref="BoolOptionRow"/> (research doc §3.3's leaf semantics apply
|
||||
/// identically; retail's <c>UIOption_Slider</c> shares the same base <c>UIOption</c>
|
||||
/// verbs as <c>UIOption_Checkbox</c>, just over a float value). <see cref="SetCurrentValue"/>
|
||||
/// is what dragging the slider thumb runs — retail's <c>SetCurrentValue → Apply(1)</c>
|
||||
/// applies LIVE, immediately, on every drag tick (not just mouse-up), which is what
|
||||
/// makes the two Chat-tab sliders visibly fade windows WHILE dragging rather than only
|
||||
/// on release.
|
||||
/// </summary>
|
||||
public sealed class FloatOptionRow : IOptionRow
|
||||
{
|
||||
private readonly Action<float>? _apply;
|
||||
private readonly Func<float>? _read;
|
||||
private readonly Action<float>? _refresh;
|
||||
private Action? _notifyPageOptionChanged;
|
||||
private float _current;
|
||||
private float _saved;
|
||||
private float _default;
|
||||
|
||||
/// <param name="read">Re-reads the LIVE value on <see cref="SaveCurrentValue"/>
|
||||
/// (OnShown/Apply) — same MUST-FIX 1 discipline as <see cref="BoolOptionRow"/>'s
|
||||
/// own <c>read</c> parameter.</param>
|
||||
/// <param name="refresh">Pushes a re-read/linked value onto the slider widget
|
||||
/// WITHOUT invoking <paramref name="apply"/> — used by both the OnShown re-seed
|
||||
/// AND by <see cref="RefreshFromLink"/> (the linked slider's own drag moving THIS
|
||||
/// row's value as a side effect, per <c>ChatOpacityLink</c>'s never-clamp-always-
|
||||
/// drag-the-other invariant).</param>
|
||||
public FloatOptionRow(
|
||||
float initial,
|
||||
float defaultValue,
|
||||
Action<float>? apply = null,
|
||||
Func<float>? read = null,
|
||||
Action<float>? refresh = null)
|
||||
{
|
||||
_current = initial;
|
||||
_saved = initial;
|
||||
_default = defaultValue;
|
||||
_apply = apply;
|
||||
_read = read;
|
||||
_refresh = refresh;
|
||||
}
|
||||
|
||||
/// <summary>The live value — what the slider thumb currently shows.</summary>
|
||||
public float Current => _current;
|
||||
|
||||
/// <summary>The committed baseline Reset reverts to.</summary>
|
||||
public float Saved => _saved;
|
||||
|
||||
/// <summary>The value Defaults restores (the DAT <c>DBProperties</c>-extracted
|
||||
/// slider default for the Chat tab's two sliders — U1's
|
||||
/// <c>InqDefaultGameplayOptionProperty</c> mechanism, this tab's genuine
|
||||
/// consumer).</summary>
|
||||
public float DefaultValue => _default;
|
||||
|
||||
public bool Changed => _saved != _current;
|
||||
|
||||
public void SetDefaultValue(float value) => _default = value;
|
||||
|
||||
/// <summary>Retail <c>SetCurrentValue</c> — the drag-tick entry point. Writes
|
||||
/// <c>m_current</c> and applies it live IMMEDIATELY; does not touch
|
||||
/// <see cref="Saved"/>.</summary>
|
||||
public void SetCurrentValue(float value)
|
||||
{
|
||||
_current = value;
|
||||
_apply?.Invoke(value);
|
||||
_notifyPageOptionChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The LINKED slider's own drag already ran <c>ChatOpacityLink</c>'s math and
|
||||
/// applied the new pair live (a single <c>RetailWindowOpacityController</c> call
|
||||
/// covers both values) — this pushes the resulting value onto THIS row/widget
|
||||
/// without re-applying (that would double-fire the live opacity write) but still
|
||||
/// notifies the page, since the OTHER slider's <c>Changed</c> baseline may now
|
||||
/// differ too (retail's <c>DualHash</c> link moves both sliders' own
|
||||
/// <c>m_current</c>).
|
||||
/// </summary>
|
||||
public void RefreshFromLink(float value)
|
||||
{
|
||||
_current = value;
|
||||
_refresh?.Invoke(value);
|
||||
_notifyPageOptionChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void AttachPageNotify(Action notify) => _notifyPageOptionChanged = notify;
|
||||
|
||||
public void SaveCurrentValue()
|
||||
{
|
||||
if (_read is not null)
|
||||
{
|
||||
_current = _read();
|
||||
_refresh?.Invoke(_current);
|
||||
}
|
||||
_saved = _current;
|
||||
}
|
||||
|
||||
public void RestoreSavedValue()
|
||||
{
|
||||
_current = _saved;
|
||||
_apply?.Invoke(_current);
|
||||
}
|
||||
|
||||
public void RestoreDefaultValue()
|
||||
{
|
||||
_current = _default;
|
||||
_apply?.Invoke(_current);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign OP slice OP5: one of the Chat tab's five per-window text-filter
|
||||
/// <c>UIOption_CheckboxBitfield64</c> blocks — the current/saved/default triple over
|
||||
/// the block's combined 64-bit filter value (retail's genuine one-register
|
||||
/// <c>m_llTextTypeFilter</c> shape; see <c>UiCheckboxBitfield64</c>'s own class doc for
|
||||
/// why the widget's <c>CurrentLow</c>/<c>CurrentHigh</c> pair is just that ONE 64-bit
|
||||
/// value split at the 32-bit boundary, not a 128-bit value). Unlike
|
||||
/// <see cref="BoolOptionRow"/>/<see cref="FloatOptionRow"/>, the WIDGET already IS the
|
||||
/// live UI for N individual checkboxes and fires <see cref="UiCheckboxBitfield64.ValueChanged"/>
|
||||
/// on any row toggle — this row wraps that composite value the same way a page needs,
|
||||
/// translating widget-originated edits into <see cref="AttachPageNotify"/>/
|
||||
/// <c>bindings.SetFilter</c> and page-originated reverts (Reset/Defaults/OnShown) into
|
||||
/// <see cref="UiCheckboxBitfield64.SetCurrentValue"/> pushes.
|
||||
/// </summary>
|
||||
public sealed class BitfieldOptionRow : IOptionRow
|
||||
{
|
||||
private readonly Action<ulong>? _apply;
|
||||
private readonly Func<ulong>? _read;
|
||||
private readonly Action<ulong>? _refresh;
|
||||
private Action? _notifyPageOptionChanged;
|
||||
private ulong _current;
|
||||
private ulong _saved;
|
||||
private ulong _default;
|
||||
|
||||
public BitfieldOptionRow(
|
||||
ulong initial,
|
||||
ulong defaultValue,
|
||||
Action<ulong>? apply = null,
|
||||
Func<ulong>? read = null,
|
||||
Action<ulong>? refresh = null)
|
||||
{
|
||||
_current = initial;
|
||||
_saved = initial;
|
||||
_default = defaultValue;
|
||||
_apply = apply;
|
||||
_read = read;
|
||||
_refresh = refresh;
|
||||
}
|
||||
|
||||
public ulong Current => _current;
|
||||
public ulong Saved => _saved;
|
||||
public ulong DefaultValue => _default;
|
||||
public bool Changed => _saved != _current;
|
||||
|
||||
public void SetDefaultValue(ulong value) => _default = value;
|
||||
|
||||
/// <summary>The widget-originated entry point — wired to
|
||||
/// <see cref="UiCheckboxBitfield64.ValueChanged"/>, fired the instant a row
|
||||
/// checkbox toggles (retail's own per-checkbox <c>Apply(1)</c>).</summary>
|
||||
public void SetCurrentValue(ulong value)
|
||||
{
|
||||
_current = value;
|
||||
_apply?.Invoke(value);
|
||||
_notifyPageOptionChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void AttachPageNotify(Action notify) => _notifyPageOptionChanged = notify;
|
||||
|
||||
public void SaveCurrentValue()
|
||||
{
|
||||
if (_read is not null)
|
||||
{
|
||||
_current = _read();
|
||||
_refresh?.Invoke(_current);
|
||||
}
|
||||
_saved = _current;
|
||||
}
|
||||
|
||||
public void RestoreSavedValue()
|
||||
{
|
||||
_current = _saved;
|
||||
_apply?.Invoke(_current);
|
||||
}
|
||||
|
||||
public void RestoreDefaultValue()
|
||||
{
|
||||
_current = _default;
|
||||
_apply?.Invoke(_current);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>OptionPage</c>/<c>PlayerOptionPage</c>: a page's registered-option
|
||||
/// array plus the four verbs (Apply/Reset/Defaults/visibility) with retail's
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue