fix(ui): scope title-bar-only-drag absorber to BeginChild — Settings tabs work
Previous fix put the InvisibleButton absorber inside Begin, which covered the entire panel body — and the Settings panel's tab bar has its hit-testing in that same area. Tabs lost click priority to the absorber (their hover/click events were stolen) so the user couldn't switch tabs. Worse, the chat-panel drag the absorber was supposed to fix wasn't actually fixed because chat's body is covered by a BeginChild for the scrollable tail — clicks land in the child window, not the parent body, so the parent absorber never sees them. Right scope: scrollable BeginChild bodies. That's where the chat panel's empty-space clicks actually land, and where the parent- drag fall-through originates. Other panels (Settings, Vitals, Debug) don't use BeginChild for content — their bodies are filled with widgets that already absorb clicks naturally. The fix: · Begin reverts to ImGui default (title bar drags, body of widget- filled panels naturally absorbs through the widgets themselves). · BeginChild grows the InvisibleButton absorber inside, so empty- space clicks inside a scroll region don't fall through to the parent's window-drag init. Net effect: · Chat panel: empty clicks in the scroll tail no longer drag the parent window. · Settings panel: tabs are clickable again. · Vitals, Debug: unchanged. dotnet build green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
627325559c
commit
2818fcca8c
1 changed files with 31 additions and 25 deletions
|
|
@ -14,30 +14,7 @@ namespace AcDream.UI.ImGui;
|
|||
public sealed class ImGuiPanelRenderer : IPanelRenderer
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool Begin(string title)
|
||||
{
|
||||
bool open = ImGuiNET.ImGui.Begin(title);
|
||||
if (open)
|
||||
{
|
||||
// Title-bar-only drag: ImGui's default lets the user drag the
|
||||
// window by clicking on the empty body background (because a
|
||||
// window-drag is initiated whenever a body click lands without
|
||||
// any widget being "active"). Filling the body with an
|
||||
// InvisibleButton absorbs those stray clicks — real widgets
|
||||
// drawn afterwards still claim their own clicks because click
|
||||
// priority is "last drawn, first checked", so the button
|
||||
// catches only empty-space clicks. Net effect: title bar
|
||||
// still drags (ImGui default), body never does.
|
||||
var avail = ImGuiNET.ImGui.GetContentRegionAvail();
|
||||
if (avail.X > 0f && avail.Y > 0f)
|
||||
{
|
||||
var savedCursor = ImGuiNET.ImGui.GetCursorPos();
|
||||
ImGuiNET.ImGui.InvisibleButton("##bodydragabsorb", avail);
|
||||
ImGuiNET.ImGui.SetCursorPos(savedCursor);
|
||||
}
|
||||
}
|
||||
return open;
|
||||
}
|
||||
public bool Begin(string title) => ImGuiNET.ImGui.Begin(title);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void End() => ImGuiNET.ImGui.End();
|
||||
|
|
@ -178,12 +155,41 @@ public sealed class ImGuiPanelRenderer : IPanelRenderer
|
|||
|
||||
/// <inheritdoc />
|
||||
public bool BeginChild(string id, Vector2 size, bool border = false)
|
||||
{
|
||||
// ImGuiChildFlags has changed names across ImGui.NET versions
|
||||
// (Border vs Borders); 0x01 is the stable bit value for "draw
|
||||
// a border". Casting from a numeric literal sidesteps the
|
||||
// version-skew without requiring a hard reference to either
|
||||
// enum spelling.
|
||||
=> ImGuiNET.ImGui.BeginChild(id, size, (ImGuiChildFlags)(border ? 0x01 : 0));
|
||||
bool open = ImGuiNET.ImGui.BeginChild(id, size, (ImGuiChildFlags)(border ? 0x01 : 0));
|
||||
if (open)
|
||||
{
|
||||
// Title-bar-only drag fix (chat tail specifically): empty
|
||||
// clicks inside a scrollable child fall through to the
|
||||
// parent window for drag-init, which is exactly what the
|
||||
// user reported in the chat panel ("clicking anywhere
|
||||
// moves the window"). An InvisibleButton sized to the
|
||||
// child's content region absorbs those clicks so they
|
||||
// don't propagate. Real widgets drawn afterwards still
|
||||
// claim their own clicks (click priority = "last drawn,
|
||||
// first checked"). Wheel scrolling is window-level, not
|
||||
// item-level, so the absorber doesn't interfere with
|
||||
// the chat tail's auto-scroll.
|
||||
//
|
||||
// Scoped to BeginChild only (NOT Begin) because Begin's
|
||||
// body might host tab bars whose hit-testing competes with
|
||||
// an absorber on equal terms — adding it at Begin level
|
||||
// broke Settings tab clicks.
|
||||
var avail = ImGuiNET.ImGui.GetContentRegionAvail();
|
||||
if (avail.X > 0f && avail.Y > 0f)
|
||||
{
|
||||
var savedCursor = ImGuiNET.ImGui.GetCursorPos();
|
||||
ImGuiNET.ImGui.InvisibleButton("##childbodyabsorb", avail);
|
||||
ImGuiNET.ImGui.SetCursorPos(savedCursor);
|
||||
}
|
||||
}
|
||||
return open;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void EndChild() => ImGuiNET.ImGui.EndChild();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue