fix: social gate round 2, part 1 - border-only move cursor, literal-\n

empty state, retail amber row selection

- Move cursor (user-directed, ALL windows): HoverWindowMove now
  advertises only where the window frame element itself wins the
  hit-test - its border pixels; interior points resolve to content
  children. Matches retail's Dragbar-chrome-only move cursor.
  Whole-surface dragging still works, it just does not advertise.
- Empty-state text (round 2): the DAT stores the LITERAL two-character
  escape backslash-n (probe-verified - the dump printed the escape, not
  line breaks), so the round-1 newline split never matched. Escapes are
  normalized before splitting in DatWidgetFactory authored text.
- Selected fellow amber (user: "check retail"): probe-verified - the
  row name band 0x10000282 AUTHORS the retail selected-row art
  (DirectState 0x06001450 + Highlight 0x06001451, the amber). Selection
  flips the band's ActiveState to Highlight; no invented tint.

App suite 4,976/3 skips. Confirmation-text + refused-drop-notification
research (the round's items 4-5) lands as part 2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-13 20:36:24 +02:00
parent 72ceddce2e
commit fc62cb6397
4 changed files with 56 additions and 5 deletions

View file

@ -637,6 +637,20 @@ public sealed class SocialPanelLiveMountProbeTests
$"[clickprobe] NOT-in-fellowship synthetic click -> optionWrites=[{string.Join(",", optionWrites)}]");
}
// The fellow row template's authored STATES (gate round 2: retail's
// selected-row amber — which element carries a Highlight/selected
// state, and what media?).
if (UiElement.FindDescendant(uiRoot, 0x10000279u) is UiTemplateListBox rosterBox
&& rosterBox.Templates.Count > 0)
{
ElementInfo? rowInfo = LayoutImporter.ImportInfos(
dats,
rosterBox.Templates[0].TemplateLayoutId,
rosterBox.Templates[0].TemplateElementId);
if (rowInfo is not null)
DumpStates(rowInfo, 0);
}
// Friends + Squelch action widgets: authored labels → button roles
// (never guess an id's role).
foreach (uint pageId in new[] { 0x10000513u, 0x1000054Au })
@ -672,6 +686,19 @@ public sealed class SocialPanelLiveMountProbeTests
return (x, y);
}
private static void DumpStates(ElementInfo info, int depth)
{
string states = string.Join(
",",
info.StateMedia.Select(kv => $"'{kv.Key}'=0x{kv.Value.File:X8}"));
Console.WriteLine(
$"[clickprobe] {new string(' ', depth * 2)}ROWSTATE 0x{info.Id:X8} type=0x{info.Type:X8} "
+ $"({info.X},{info.Y} {info.Width}x{info.Height}) default='{info.DefaultStateName}' "
+ $"media=[{states}]");
foreach (ElementInfo c in info.Children)
DumpStates(c, depth + 1);
}
private static void DumpActionWidgets(UiElement el, int depth)
{
string extra = el switch