fix(ui): #145 — importer honors ZLevel so the backdrop sits behind panels
The factory mapped ZOrder from ReadOrder only, so the gmInventoryUI full-window backdrop (0x100001D0, ReadOrder 4) painted over the nested panels (ReadOrder 1-3). Wire ElementDesc.ZLevel through ElementInfo / ToInfo / Merge and fold it into ZOrder = ReadOrder - ZLevel*10000 (higher ZLevel = further back, ReadOrder the within-layer tiebreaker). Vitals (all ZLevel 0) are unchanged; chat (ZLevel 900) + toolbar (1,2) shift to their dat layering — verify visually. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d81ea11a31
commit
45a5cc5bb6
4 changed files with 56 additions and 2 deletions
|
|
@ -77,8 +77,11 @@ public static class DatWidgetFactory
|
||||||
e.Width = info.Width;
|
e.Width = info.Width;
|
||||||
e.Height = info.Height;
|
e.Height = info.Height;
|
||||||
|
|
||||||
// Honor the dat's draw order so overlapping pieces (grip overlay over bevel chrome) layer correctly.
|
// Honor the dat's draw order. ZLevel is the primary layer (higher = further BACK — e.g. the
|
||||||
e.ZOrder = (int)info.ReadOrder;
|
// gmInventoryUI full-window backdrop at ZLevel 100 sits behind the ZLevel-0 panels, #145);
|
||||||
|
// ReadOrder is the within-layer tiebreaker (higher = on top). K=10000 exceeds any window's
|
||||||
|
// element count so ZLevel always dominates. Vitals (all ZLevel 0) keep ZOrder == ReadOrder.
|
||||||
|
e.ZOrder = (int)info.ReadOrder - (int)info.ZLevel * 10000;
|
||||||
|
|
||||||
// Map the four raw edge-anchor values to the AnchorEdges bit-flag that the
|
// Map the four raw edge-anchor values to the AnchorEdges bit-flag that the
|
||||||
// UI layout engine uses for reflow.
|
// UI layout engine uses for reflow.
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,12 @@ public sealed class ElementInfo
|
||||||
/// <summary>Draw order within the parent (lower = drawn first / behind).</summary>
|
/// <summary>Draw order within the parent (lower = drawn first / behind).</summary>
|
||||||
public uint ReadOrder;
|
public uint ReadOrder;
|
||||||
|
|
||||||
|
/// <summary>Layer level from the dat (<c>ElementDesc.ZLevel</c>). Higher = drawn further
|
||||||
|
/// BACK (a full-window backdrop at ZLevel 100 sits behind ZLevel-0 panels). The factory
|
||||||
|
/// folds it into <see cref="UiElement.ZOrder"/> so ZLevel dominates and ReadOrder is the
|
||||||
|
/// within-layer tiebreaker. Issue #145 (vitals are all ZLevel 0, so they're unaffected).</summary>
|
||||||
|
public uint ZLevel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Font dat object id inherited from the base element's <c>Properties[0x1A]</c>
|
/// Font dat object id inherited from the base element's <c>Properties[0x1A]</c>
|
||||||
/// (<c>ArrayBaseProperty → DataIdBaseProperty</c>). 0 = none / not inherited.
|
/// (<c>ArrayBaseProperty → DataIdBaseProperty</c>). 0 = none / not inherited.
|
||||||
|
|
@ -152,6 +158,7 @@ public static class ElementReader
|
||||||
Right = derived.Right,
|
Right = derived.Right,
|
||||||
Bottom = derived.Bottom,
|
Bottom = derived.Bottom,
|
||||||
ReadOrder = derived.ReadOrder,
|
ReadOrder = derived.ReadOrder,
|
||||||
|
ZLevel = derived.ZLevel != 0 ? derived.ZLevel : base_.ZLevel,
|
||||||
FontDid = derived.FontDid != 0 ? derived.FontDid : base_.FontDid,
|
FontDid = derived.FontDid != 0 ? derived.FontDid : base_.FontDid,
|
||||||
// DefaultStateName: derived wins if set; otherwise inherit the base's default.
|
// DefaultStateName: derived wins if set; otherwise inherit the base's default.
|
||||||
DefaultStateName = !string.IsNullOrEmpty(derived.DefaultStateName) ? derived.DefaultStateName : base_.DefaultStateName,
|
DefaultStateName = !string.IsNullOrEmpty(derived.DefaultStateName) ? derived.DefaultStateName : base_.DefaultStateName,
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,7 @@ public static class LayoutImporter
|
||||||
Right = d.RightEdge,
|
Right = d.RightEdge,
|
||||||
Bottom = d.BottomEdge,
|
Bottom = d.BottomEdge,
|
||||||
ReadOrder = d.ReadOrder,
|
ReadOrder = d.ReadOrder,
|
||||||
|
ZLevel = d.ZLevel,
|
||||||
DefaultStateName = (defState is "Undef" or "Undefined" or "0") ? "" : defState,
|
DefaultStateName = (defState is "Undef" or "Undefined" or "0") ? "" : defState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
43
tests/AcDream.App.Tests/UI/DatWidgetFactoryZOrderTests.cs
Normal file
43
tests/AcDream.App.Tests/UI/DatWidgetFactoryZOrderTests.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using AcDream.App.UI.Layout;
|
||||||
|
|
||||||
|
namespace AcDream.App.Tests.UI;
|
||||||
|
|
||||||
|
public class DatWidgetFactoryZOrderTests
|
||||||
|
{
|
||||||
|
private static (uint, int, int) NoChrome(uint id) => (0u, 0, 0);
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ZOrder_HigherZLevel_DrawsBehind()
|
||||||
|
{
|
||||||
|
// The gmInventoryUI backdrop (ZLevel 100, ReadOrder 4) must draw BEHIND the panels
|
||||||
|
// (ZLevel 0, ReadOrder 1): lower ZOrder = drawn first = behind. Before the fix, ZOrder
|
||||||
|
// came from ReadOrder only, so the backdrop (4) painted over the panels (1).
|
||||||
|
var backdrop = new ElementInfo { Type = 3, ReadOrder = 4, ZLevel = 100 };
|
||||||
|
var panel = new ElementInfo { Type = 3, ReadOrder = 1, ZLevel = 0 };
|
||||||
|
|
||||||
|
var b = DatWidgetFactory.Create(backdrop, NoChrome, null);
|
||||||
|
var p = DatWidgetFactory.Create(panel, NoChrome, null);
|
||||||
|
|
||||||
|
Assert.True(b!.ZOrder < p!.ZOrder, $"backdrop ZOrder {b.ZOrder} should be < panel ZOrder {p.ZOrder}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ZOrder_AllZeroZLevel_EqualsReadOrder()
|
||||||
|
{
|
||||||
|
// Regression guard: a vitals-style window (every element ZLevel 0) keeps ZOrder == ReadOrder.
|
||||||
|
var e = new ElementInfo { Type = 3, ReadOrder = 5, ZLevel = 0 };
|
||||||
|
var w = DatWidgetFactory.Create(e, NoChrome, null);
|
||||||
|
Assert.Equal(5, w!.ZOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ZOrder_SameZLevel_OrderedByReadOrder()
|
||||||
|
{
|
||||||
|
// Within one ZLevel, ReadOrder is the tiebreaker (higher ReadOrder draws on top).
|
||||||
|
var lo = new ElementInfo { Type = 3, ReadOrder = 2, ZLevel = 2 };
|
||||||
|
var hi = new ElementInfo { Type = 3, ReadOrder = 7, ZLevel = 2 };
|
||||||
|
var l = DatWidgetFactory.Create(lo, NoChrome, null);
|
||||||
|
var h = DatWidgetFactory.Create(hi, NoChrome, null);
|
||||||
|
Assert.True(l!.ZOrder < h!.ZOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue