fix(ui): retain character sublayout reflow

This commit is contained in:
Erik 2026-07-10 18:20:11 +02:00
parent accacecafe
commit f684f874df
2 changed files with 64 additions and 9 deletions

View file

@ -447,16 +447,20 @@ public static class CharacterStatController
? FindInSubtree(contentPage, static el => HasDatElementId(el, ListBoxId)) ? FindInSubtree(contentPage, static el => HasDatElementId(el, ListBoxId))
: null) : null)
?? layout.FindElement(ListBoxId); ?? layout.FindElement(ListBoxId);
if (statList is not null) // Imported character nodes already carry the exact raw-edge policy from
// the 337px base sublayout into the 575px mounted page. Only synthetic/
// legacy widgets need compatibility anchors; assigning Anchors on an
// imported node deliberately clears its UiLayoutPolicy.
if (statList is not null && statList.LayoutPolicy is null)
statList.Anchors = AnchorEdges.Left | AnchorEdges.Top | AnchorEdges.Bottom; statList.Anchors = AnchorEdges.Left | AnchorEdges.Top | AnchorEdges.Bottom;
if (layout.Root is { } stretchRoot) if (layout.Root is { } stretchRoot)
{ {
SetAnchorsAllById(stretchRoot, ListScrollbarId, AnchorEdges.Left | AnchorEdges.Top | AnchorEdges.Bottom); SetCompatibilityAnchorsAllById(stretchRoot, ListScrollbarId, AnchorEdges.Left | AnchorEdges.Top | AnchorEdges.Bottom);
SetAnchorsAllById(stretchRoot, ListDividerId, AnchorEdges.Left | AnchorEdges.Bottom); SetCompatibilityAnchorsAllById(stretchRoot, ListDividerId, AnchorEdges.Left | AnchorEdges.Bottom);
SetAnchorsAllById(stretchRoot, FooterStateAId, AnchorEdges.Left | AnchorEdges.Bottom); SetCompatibilityAnchorsAllById(stretchRoot, FooterStateAId, AnchorEdges.Left | AnchorEdges.Bottom);
SetAnchorsAllById(stretchRoot, FooterStateBId, AnchorEdges.Left | AnchorEdges.Bottom); SetCompatibilityAnchorsAllById(stretchRoot, FooterStateBId, AnchorEdges.Left | AnchorEdges.Bottom);
SetAnchorsAllById(stretchRoot, FooterStateCId, AnchorEdges.Left | AnchorEdges.Bottom); SetCompatibilityAnchorsAllById(stretchRoot, FooterStateCId, AnchorEdges.Left | AnchorEdges.Bottom);
} }
UiScrollbar? skillScrollbar = PrepareSkillScrollbar(layout, contentPage, statList, spriteResolve); UiScrollbar? skillScrollbar = PrepareSkillScrollbar(layout, contentPage, statList, spriteResolve);
@ -1637,12 +1641,19 @@ public static class CharacterStatController
// ── Helpers ────────────────────────────────────────────────────────────── // ── Helpers ──────────────────────────────────────────────────────────────
private static void SetAnchorsAllById(UiElement node, uint targetId, AnchorEdges anchors) private static void SetCompatibilityAnchorsAllById(
UiElement node,
uint targetId,
AnchorEdges anchors)
{ {
if (node is UiDatElement d && d.ElementId == targetId) if (node is UiDatElement d
&& d.ElementId == targetId
&& node.LayoutPolicy is null)
{
node.Anchors = anchors; node.Anchors = anchors;
}
foreach (var child in node.Children) foreach (var child in node.Children)
SetAnchorsAllById(child, targetId, anchors); SetCompatibilityAnchorsAllById(child, targetId, anchors);
} }
/// <summary>Depth-first search of <paramref name="node"/> and its descendants. /// <summary>Depth-first search of <paramref name="node"/> and its descendants.

View file

@ -1471,6 +1471,41 @@ public class CharacterStatControllerTests
Assert.NotNull(meter.Fill()); Assert.NotNull(meter.Fill());
} }
[Fact]
public void ProductionFixture_MountedPagesUseRetailListFooterAndScrollbarReflow()
{
var layout = FixtureLoader.LoadCharacter();
CharacterStatController.Bind(
layout,
SampleData.SampleCharacter,
spriteResolve: id => (id, 16, 16));
ApplyLayoutPass(layout.Root);
var page = layout.Root.Children.Single(
e => e.DatElementId == CharacterStatController.AttributesPageId);
var list = Descendants(page).Single(
e => e.DatElementId == CharacterStatController.ListBoxId);
var statLayout = list.Parent!;
var scrollbar = statLayout.Children.OfType<UiScrollbar>().Single(
e => e.DatElementId == CharacterStatController.ListScrollbarId);
var divider = statLayout.Children.Single(
e => e.DatElementId == CharacterStatController.ListDividerId);
var footers = statLayout.Children.Where(
e => e.DatElementId is CharacterStatController.FooterStateAId
or CharacterStatController.FooterStateBId
or CharacterStatController.FooterStateCId).ToList();
Assert.Equal((112f, 398f), (list.Top, list.Height));
Assert.Equal((112f, 398f), (scrollbar.Top, scrollbar.Height));
Assert.Equal((510f, 7f), (divider.Top, divider.Height));
Assert.Equal(3, footers.Count);
Assert.All(footers, footer => Assert.Equal((520f, 55f), (footer.Top, footer.Height)));
ClickTab(layout, left: 92f);
Assert.True(scrollbar.Visible);
}
// ── Helpers ────────────────────────────────────────────────────────────── // ── Helpers ──────────────────────────────────────────────────────────────
private static void ClickTab(ImportedLayout layout, float left) private static void ClickTab(ImportedLayout layout, float left)
@ -1482,6 +1517,15 @@ public class CharacterStatControllerTests
tab.OnClick!(); tab.OnClick!();
} }
private static void ApplyLayoutPass(UiElement parent)
{
foreach (var child in parent.Children)
{
child.ApplyAnchor(parent.Width, parent.Height);
ApplyLayoutPass(child);
}
}
private static string FirstRowName(UiElement list) private static string FirstRowName(UiElement list)
{ {
var row = Descendants(list).OfType<UiClickablePanel>().FirstOrDefault(); var row = Descendants(list).OfType<UiClickablePanel>().FirstOrDefault();