feat(D.2b): chat text selection + Ctrl-C copy
Windows-like selection in the retail chat window: left-click-drag selects characters, Ctrl-C copies, Ctrl-A selects all. The selected span paints a translucent highlight behind the text. - UiElement.CapturesPointerDrag: a per-element opt-out so an interior drag is delivered to the widget (text selection) instead of moving/resizing the host window. UiRoot.OnMouseDown honours it AFTER edge-resize (a resizable window is still resizable from its frame) and BEFORE window-move. - UiChatView: AcceptsFocus + IsEditControl + CapturesPointerDrag; caches the OnDraw layout so OnEvent hit-tests the same geometry; HitChar maps a local point to (line,col) with glyph-midpoint caret snapping; SelectedText joins a multi-line span with \n; Ctrl-C writes to IKeyboard.ClipboardText (only when non-empty, so an empty copy never clobbers the clipboard). - UiHost exposes the wired IKeyboard (clipboard + Ctrl modifier state). Adversarial-review fix (the 99 tests would have stayed green without it): a coordinate-frame mismatch between MouseDown and MouseMove. UiRoot.OnMouseDown dispatched HitTestTopDown's coords, which are relative to the TOP-LEVEL child, while MouseMove/MouseUp use target.ScreenPosition. For the chat view inset at (8,8) inside its window the anchor landed ~8px off the click. OnMouseDown now delivers target-LOCAL coords like the other mouse events. Added a UiRoot regression test asserting MouseDown and MouseMove share the target-local frame for a nested child. Decomp ref: SurfaceWindow text/selection model; clipboard via Silk.NET IKeyboard.ClipboardText. Built with the chat-select-copy implement->review workflow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
36bd3522f4
commit
4e60c03a74
7 changed files with 507 additions and 12 deletions
|
|
@ -39,6 +39,13 @@ public sealed class UiHost : System.IDisposable
|
|||
public UiRoot Root { get; } = new();
|
||||
public TextRenderer TextRenderer { get; }
|
||||
public BitmapFont? DefaultFont { get; set; }
|
||||
|
||||
/// <summary>The last wired keyboard. Exposed so widgets that need clipboard
|
||||
/// access (<see cref="IKeyboard.ClipboardText"/>) or modifier-key state
|
||||
/// (<see cref="IKeyboard.IsKeyPressed"/>) — e.g. <see cref="UiChatView"/>'s
|
||||
/// Ctrl+C copy — can reach the device. One-keyboard desktop: last wins.</summary>
|
||||
public IKeyboard? Keyboard { get; private set; }
|
||||
|
||||
private long _startTicks = System.Environment.TickCount64;
|
||||
|
||||
public UiHost(GL gl, string shaderDir, BitmapFont? defaultFont = null)
|
||||
|
|
@ -82,6 +89,7 @@ public sealed class UiHost : System.IDisposable
|
|||
|
||||
public void WireKeyboard(IKeyboard kb)
|
||||
{
|
||||
Keyboard = kb; // last wired keyboard wins (one-keyboard desktop)
|
||||
kb.KeyDown += (_, k, _) => Root.OnKeyDown((int)k);
|
||||
kb.KeyUp += (_, k, _) => Root.OnKeyUp((int)k);
|
||||
kb.KeyChar += (_, c) => Root.OnChar(c);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue