fix(combat): preserve authored meter child geometry

Carry the consumed dark-range child's own retail edge policy into the procedural scrollbar, widening it to the authored post-reflow interval without covering the rendered labels. Restore the bright layer to live attack-charge feedback across the full bar from the left.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-12 21:57:53 +02:00
parent f8c174d707
commit e671b8a5c4
10 changed files with 66 additions and 105 deletions

View file

@ -93,8 +93,7 @@ public sealed class CombatUiController : IRetainedPanelController
_powerControl.SetScalarPosition(_attacks.DesiredPower);
_powerControl.ScalarChanged = _attacks.SetDesiredPower;
_powerControl.ScalarFill = () => null;
_powerControl.ScalarFillFollowsThumb = true;
_powerControl.ScalarFill = () => _attacks.PowerBarLevel;
BindAttackButton(_high, AttackHeight.High);
BindAttackButton(_medium, AttackHeight.Medium);
@ -110,7 +109,6 @@ public sealed class CombatUiController : IRetainedPanelController
UiText? powerLabel = layout.FindElement(PowerLabelId) as UiText;
SetStaticText(speedLabel, labels.Speed, rightAligned: false);
SetStaticText(powerLabel, labels.Power, rightAligned: true);
ConfigurePowerRange(speedLabel, powerLabel);
_repeatAttacks.OnClick = () =>
_setGameplay(_gameplay() with { AutoRepeatAttack = _repeatAttacks.Selected });
@ -194,24 +192,6 @@ public sealed class CombatUiController : IRetainedPanelController
_keepInView.Selected = gameplay.ViewCombatTarget;
}
private void ConfigurePowerRange(UiText? speedLabel, UiText? powerLabel)
{
if (speedLabel is null || powerLabel is null) return;
// All three elements are siblings in gmCombatUI's basic page. Keeping
// the meter between the authored text rectangles leaves the base gray
// track behind Speed/Power while the dark/live red textures occupy the
// semantic power range between them.
_powerControl.ScalarRangeProvider = () =>
{
float left = speedLabel.Left + speedLabel.Width - _powerControl.Left;
float right = powerLabel.Left - _powerControl.Left;
float clampedLeft = Math.Clamp(left, 0f, _powerControl.Width);
return (clampedLeft, Math.Max(
0f, Math.Clamp(right, 0f, _powerControl.Width) - clampedLeft));
};
}
private static void SetStaticText(UiText? text, string value, bool rightAligned)
{
if (text is null) return;
@ -236,8 +216,6 @@ public sealed class CombatUiController : IRetainedPanelController
_attacks.StateChanged -= OnAttackStateChanged;
_powerControl.ScalarChanged = null;
_powerControl.ScalarFill = () => null;
_powerControl.ScalarFillFollowsThumb = false;
_powerControl.ScalarRangeProvider = null;
_high.OnPressed = null;
_high.OnReleased = null;
_medium.OnPressed = null;

View file

@ -110,23 +110,7 @@ public static class DatWidgetFactory
// design parent and intentionally remain on the compatibility path until a
// window mount assigns its own outer-frame policy.
if (info.HasOriginalParentSize)
{
e.LayoutPolicy = new UiLayoutPolicy(
info.Left,
info.Top,
info.Right,
info.Bottom,
UiPixelRect.FromPositionAndSize(
(int)info.X,
(int)info.Y,
(int)info.Width,
(int)info.Height),
UiPixelRect.FromPositionAndSize(
0,
0,
(int)info.OriginalParentWidth,
(int)info.OriginalParentHeight));
}
e.LayoutPolicy = CreateLayoutPolicy(info);
return e;
}
@ -186,6 +170,9 @@ public static class DatWidgetFactory
bar.ScalarRangeSprite = scalarRange is null
? 0u
: DefaultImage(scalarRange);
bar.ScalarRangeLayoutPolicy = scalarRange is null
? null
: CreateLayoutPolicy(scalarRange);
// UIElement_Meter::UIElement_Meter @ 0x0046F4C0 defaults direction
// 1; DrawChildren @ 0x0046FBD0 clips that direction left-to-right.
// Direction 3 is the horizontal reverse. Read authored attribute
@ -221,6 +208,26 @@ public static class DatWidgetFactory
return bar;
}
private static UiLayoutPolicy? CreateLayoutPolicy(ElementInfo info)
{
if (!info.HasOriginalParentSize) return null;
return new UiLayoutPolicy(
info.Left,
info.Top,
info.Right,
info.Bottom,
UiPixelRect.FromPositionAndSize(
(int)info.X,
(int)info.Y,
(int)info.Width,
(int)info.Height),
UiPixelRect.FromPositionAndSize(
0,
0,
(int)info.OriginalParentWidth,
(int)info.OriginalParentHeight));
}
private static uint ReferencedElementId(ElementInfo info, uint propertyId)
{
if (!info.TryGetEffectiveProperty(propertyId, out var property))