feat(chat): CT-A5 — clicking a speaker's name opens a tell
Campaign CT slice A5, closing Group A. Retail's
gmMainChatUI::RecvNotice_TextTag_IIDStringClick @0x004CCE10 ->
ChatInterface::StartTell @0x004F41F0 writes "@tell {Name}, " into the chat
entry and takes keyboard focus; clicking a green name here now does the same.
The trailing space is deliberate — without it the first character the player
types joins the comma.
Three seams, each narrow on purpose:
- UiText.OnCharClick is offered the character under a left click before the
element-wide OnClick, and consuming it suppresses that. Kept separate
because a tag click is POSITIONAL and an element click is not; folding
them together would make every text element with an OnClick swallow tag
clicks.
- TaggedRangesForFragment returns tagged column ranges relative to the
FRAGMENT, because that is what a click resolves to — UiText.HitChar gives
a line index into the WRAPPED list plus a column within it. Line-relative
ranges would land every click on a wrapped line at the wrong characters.
- The controller caches those ranges alongside the runs it already caches,
so the per-click lookup reads the same cache the draw does.
The hit test is half-open: a caret slot sits BETWEEN glyphs, so clicking just
past a name's last letter belongs to the space after it, not the name. Pinned
by theory rather than left to chance, since off-by-one here means clicking a
name sometimes does nothing.
StartTell uses the tag's NAME, not its object id — retail carries the id but
this handler never reads it, so the tell still addresses correctly for someone
who has since moved out of range.
Group A is complete: names are green (A4) and clickable (A5). Ready for the
user's visual gate.
Solution builds clean; full hermetic gate green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
53395e4de4
commit
d32ef388f0
5 changed files with 245 additions and 7 deletions
|
|
@ -158,6 +158,25 @@ public class ChatWindowControllerTests
|
|||
Assert.NotNull(ctrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartTell_PrefillsTheEntryAndPutsTheCaretAtTheEnd()
|
||||
{
|
||||
// Retail's ChatInterface::StartTell @0x004F41F0 writes "@tell {Name}, "
|
||||
// into the chat entry and takes focus, so the player can type straight
|
||||
// into a reply. The trailing space matters: without it the first thing
|
||||
// they type joins the comma.
|
||||
var (rootInfo, layout, vm) = BuildTestTree();
|
||||
var bus = new CaptureBus();
|
||||
|
||||
ChatWindowController? ctrl = ChatWindowController.Bind(
|
||||
rootInfo, layout, vm, () => bus, new ChatWindowState(), null, null, NoTex);
|
||||
Assert.NotNull(ctrl);
|
||||
|
||||
ctrl!.StartTell("Dww");
|
||||
|
||||
Assert.Equal("@tell Dww, ", ctrl.Input.Text);
|
||||
}
|
||||
|
||||
// ── Talk-focus specials: "Tell to X" / "Squelch (ignore) X" ─────────────
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue