feat(studio): forward canvas mouse to the previewed panel (interactive preview)
Canvas clicks now reach the panel UiHost so buttons, tabs, and slots respond to user interaction. Previously only UiRoot.Pick (inspector selection) received click events; the panel itself was inert. Key changes: - StudioInspector.DrawCanvas now returns a CanvasInputEvent struct (was nullable click tuple) — carries isHovered, move position, leftDown/Up, and scroll delta, all in panel-local pixels. - Coordinate mapping: panel_local = mouse_screen - GetItemRectMin() (1:1, no scale factor). V-flip (uv0.Y=1, uv1.Y=0) makes screen top = panel Y=0, so NO extra Y inversion. Documented in comments. - StudioWindow.OnLoad: removed WireMouse — raw Silk window coords are offset by the canvas sub-window position and land in the wrong place. WireKeyboard kept (keyboard input needs no spatial remapping). - StudioWindow.OnRender: forwards OnMouseMove always (hover states), plus OnMouseDown/Up/OnScroll in Interact mode. Console.WriteLine on each forwarded left-click for live verification. - Interact/Inspect toggle: checkbox in the Studio toolbar (default Interact). Inspect mode restores old click-to-select-element behavior while still forwarding OnMouseMove for hover states. - CanvasCoordMappingTests: 7 pure-math unit tests covering the origin, interior points, corner, chrome OOB, and the no-extra-flip invariant (no GL required). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eccacc59de
commit
21d8485053
3 changed files with 280 additions and 62 deletions
|
|
@ -183,9 +183,10 @@ public sealed class StudioWindow : IDisposable
|
|||
if (_opts.ScreenshotPath is null)
|
||||
{
|
||||
var input = _window!.CreateInput();
|
||||
// Wire input into UiHost (interactive only).
|
||||
foreach (var mouse in input.Mice)
|
||||
_stack.UiHost.WireMouse(mouse);
|
||||
// Wire KEYBOARD input into UiHost (keyboard coords are not spatial, so no remapping needed).
|
||||
// Do NOT wire mouse here — raw Silk window coords would be offset by the canvas sub-window's
|
||||
// position (tree pane width + ImGui chrome) and land in the wrong panel-local location.
|
||||
// Mouse is forwarded manually from DrawCanvas with correct panel-local mapping below.
|
||||
foreach (var kb in input.Keyboards)
|
||||
_stack.UiHost.WireKeyboard(kb);
|
||||
_imgui = new AcDream.UI.ImGui.ImGuiBootstrapper(gl, _window!, input);
|
||||
|
|
@ -319,21 +320,57 @@ public sealed class StudioWindow : IDisposable
|
|||
if (pickedSlug is not null)
|
||||
LoadDumpPanel(pickedSlug);
|
||||
|
||||
// 6. Canvas pane — show the FBO texture; detect clicks.
|
||||
(int x, int y)? click = null;
|
||||
// 6. Canvas pane — show the FBO texture; gather canvas mouse events.
|
||||
var canvasEvt = default(CanvasInputEvent);
|
||||
if (panelTex != 0)
|
||||
click = _inspector.DrawCanvas(
|
||||
canvasEvt = _inspector.DrawCanvas(
|
||||
(nint)panelTex, iw, ih,
|
||||
canvasX, canvasW, paneY, paneH);
|
||||
|
||||
// 7. If the user clicked inside the canvas, hit-test the whole UI tree (UiRoot.Pick honors
|
||||
// Z-order + modal exclusivity) and select the topmost element. The canvas click coord is
|
||||
// in the same root-space the FBO was drawn in, so it maps 1:1.
|
||||
if (click is { } c)
|
||||
// 7. Forward canvas mouse events to the panel UiHost or the inspector tree.
|
||||
//
|
||||
// Coordinate mapping (see StudioInspector.DrawCanvas summary):
|
||||
// panel-local pixel = raw_mouse - ImGui.GetItemRectMin() (1:1 scale, no Y flip)
|
||||
// The image is drawn V-flipped (uv0.Y=1, uv1.Y=0) so screen top = panel Y=0.
|
||||
//
|
||||
// Interact mode (default): canvas mouse events go directly to UiRoot so elements respond.
|
||||
// OnMouseMove + OnMouseDown/Up + OnScroll are all forwarded.
|
||||
// A Console.WriteLine confirms each forwarded left-click for live verification.
|
||||
//
|
||||
// Inspect mode: left-click hit-tests and selects the element in the tree (old behavior).
|
||||
// OnMouseMove is still forwarded so hover/tooltip state in the panel stays live.
|
||||
if (canvasEvt.IsHovered)
|
||||
{
|
||||
var hit = _stack.UiHost.Root.Pick(c.x, c.y);
|
||||
if (hit is not null)
|
||||
_inspector.Selected = hit;
|
||||
int mx = canvasEvt.MouseX;
|
||||
int my = canvasEvt.MouseY;
|
||||
var root = _stack.UiHost.Root;
|
||||
|
||||
// Always forward mouse-move so hover highlights / tooltips in the panel work.
|
||||
root.OnMouseMove(mx, my);
|
||||
|
||||
if (_inspector.InteractMode)
|
||||
{
|
||||
// ── Interact: live panel interaction ──────────────────────────────
|
||||
if (canvasEvt.LeftDown)
|
||||
{
|
||||
Console.WriteLine($"[studio] canvas click → panel ({mx}, {my})");
|
||||
root.OnMouseDown(UiMouseButton.Left, mx, my);
|
||||
}
|
||||
if (canvasEvt.LeftUp)
|
||||
root.OnMouseUp(UiMouseButton.Left, mx, my);
|
||||
if (canvasEvt.ScrollDelta != 0)
|
||||
root.OnScroll(canvasEvt.ScrollDelta);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ── Inspect: click selects an element in the tree ─────────────────
|
||||
if (canvasEvt.LeftDown)
|
||||
{
|
||||
var hit = root.Pick(mx, my);
|
||||
if (hit is not null)
|
||||
_inspector.Selected = hit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Element tree pane.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue