namespace AcDream.UI.Abstractions.Panels.Settings;
///
/// Retail's linked default/active window-opacity invariant: active >= default,
/// ALWAYS — enforced by dragging the OTHER value, never by clamping the one being
/// set. Verbatim port of ChatInterface::SetDefaultOpacity @0x004F3BC0 /
/// SetActiveOpacity @0x004F3C40 (docs/research/2026-08-09-chat-retail-window-shell.md
/// §3): raising the default ABOVE the current active value drags active UP to match;
/// lowering the active value BELOW the current default drags default DOWN to match.
/// Retail's options-page sliders share a DualHash link
/// (gmChatOptionsUI::InitOptions @0x0049FC60) — this is why they visibly track
/// each other while dragging.
///
///
/// Shared by two independent consumers so both apply the identical link math:
/// RetailWindowOpacityController (AcDream.App — the live per-window
/// mechanism, mutating its own two float fields) and 's
/// Chat tab (the draft slider UI, mutating a record).
/// Pure functions — no window/render/state dependency — so both layers can call
/// them without violating the App→Abstractions dependency direction.
///
///
public static class ChatOpacityLink
{
///
/// Port of ChatInterface::SetDefaultOpacity @0x004F3BC0: set the default
/// (unfocused) opacity to , dragging
/// UP if it would otherwise fall below the new
/// default. Never returns an (default, active) pair with active < default.
///
public static (float DefaultOpacity, float ActiveOpacity) SetDefault(
float currentActive, float newDefault)
{
newDefault = System.Math.Clamp(newDefault, 0f, 1f);
float active = currentActive < newDefault ? newDefault : currentActive;
return (newDefault, active);
}
///
/// Port of ChatInterface::SetActiveOpacity @0x004F3C40: set the active
/// (focused) opacity to , dragging
/// DOWN if it would otherwise exceed the new
/// active value. Never returns an (default, active) pair with active < default.
///
public static (float DefaultOpacity, float ActiveOpacity) SetActive(
float currentDefault, float newActive)
{
newActive = System.Math.Clamp(newActive, 0f, 1f);
float def = currentDefault > newActive ? newActive : currentDefault;
return (def, newActive);
}
}