fix(vendor): gate-findings pass — the X button HIDES like retail, clicks return, the dropdown scrolls, pyreal suffix, staged-tab slots
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run

The user's connected gate found five issues; each fixed at the root:

G4 (the discovery): retail's vendor X button calls only SetVisible(0)
(pc:204147-204182) — the SESSION stays open and re-using the vendor
lands on the same-session refresh; the range watcher remains the sole
real close. Our port invented a full teardown on X, which is exactly
why reopening died. The Runtime fixture proves the wire dispatch was
never the problem; ACE has no already-open short-circuit.

G3 (regression from the drag-suppression fix): denying IsDragSource
also dropped press capture, so clicks fell through to window-drag.
UiItemSlot.HandlesClick now claims presses for any occupied cell
independent of drag eligibility — clickable and draggable are separate
concerns.

G5: the authored popup 0x21000043 is ONE scrollable column with a real
scrollbar subtree (live-dat scan: ListBox 0x10000350 + scrollbar
0x10000351), not a 3x6 grid. UiMenu gains an authored-driven
Scrollable mode (wheel, thumb drag, track paging, up/down buttons);
chat's menu is untouched and its ten tests prove it.

G1: retail's cost format is "%s %hsp (you have %hsp)" — the p after
each %hs is a LITERAL pyreal suffix the port swallowed as part of the
specifier. Restored.

G2: the Buying/Selling pages' authored lists (same cell template as
Items) get the empty-slot fill, presentation-only until staging.

Clean-room complete solution: 11,390 passed / 4 skipped / 0 failed.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-08 10:29:39 +02:00
parent 58c8de264e
commit 5224e43890
8 changed files with 1061 additions and 51 deletions

View file

@ -1943,6 +1943,8 @@ public sealed class RetailUiRuntime : IDisposable
{
ImportedLayout? layout;
uint emptySlotSprite;
uint buyingEmptySlotSprite;
uint sellingEmptySlotSprite;
lock (_bindings.Assets.DatLock)
{
layout = LayoutImporter.Import(
@ -1959,6 +1961,18 @@ public sealed class RetailUiRuntime : IDisposable
_bindings.Assets.Dats,
VendorUiController.LayoutId,
VendorUiController.ItemListId);
// G2 (vendor gate finding): the Buying/Selling pages author
// their OWN item strips (same cell-template prototype as the
// Items list per the fixture, but resolved independently here
// rather than assumed identical).
buyingEmptySlotSprite = ItemListCellTemplate.ResolveEmptySprite(
_bindings.Assets.Dats,
VendorUiController.LayoutId,
VendorUiController.BuyingListId);
sellingEmptySlotSprite = ItemListCellTemplate.ResolveEmptySprite(
_bindings.Assets.Dats,
VendorUiController.LayoutId,
VendorUiController.SellingListId);
}
if (layout is null)
{
@ -2013,7 +2027,9 @@ public sealed class RetailUiRuntime : IDisposable
_bindings.Assets.DefaultFont,
_bindings.Assets.DebugFont,
_bindings.Assets.ResolveSprite,
emptySlotSprite);
emptySlotSprite,
buyingEmptySlotSprite,
sellingEmptySlotSprite);
if (VendorController is null)
{
Console.WriteLine("[M4] vendor: required authored controls are missing.");